dbus-1.10.6/0000755000175000017500000000000012627367774012563 5ustar00smcvsmcv00000000000000dbus-1.10.6/doc/0000755000175000017500000000000012627367775013331 5ustar00smcvsmcv00000000000000dbus-1.10.6/doc/introspect.dtd0000644000175000017500000000230212602773110016166 0ustar00smcvsmcv00000000000000 dbus-1.10.6/doc/busconfig.dtd0000644000175000017500000000356312602773110015765 0ustar00smcvsmcv00000000000000 dbus-1.10.6/doc/introspect.xsl0000644000175000017500000000733312602773110016232 0ustar00smcvsmcv00000000000000 DBUS Introspection data

interface

    • out in
  • annotation =
  • dbus-1.10.6/doc/dcop-howto.txt0000644000175000017500000005132012602773110016127 0ustar00smcvsmcv00000000000000 DCOP: Desktop COmmunications Protocol Preston Brown October 14, 1999 Revised and extended by Matthias Ettrich Mar 29, 2000 Extended with DCOP Signals by Waldo Bastian Feb 19, 2001 Motivation and Background: -------------------------- The motivation behind building a protocol like DCOP is simple. For the past year, we have been attempting to enable interprocess communication between KDE applications. KDE already has an extremely simple IPC mechanism called KWMcom, which is (was!) used for communicating between the panel and the window manager for instance. It is about as simple as it gets, passing messages via X Atoms. For this reason it is limited in the size and complexity of the data that can be passed (X atoms must be small to remain efficient) and it also makes it so that X is required. CORBA was thought to be a more effective IPC/RPC solution. However, after a year of attempting to make heavy use of CORBA in KDE, we have realized that it is a bit slow and memory intensive for simple use. It also has no authentication available. What we really needed was an extremely simple protocol with basic authorization, along the lines of MIT-MAGIC-COOKIE, as used by X. It would not be able to do NEARLY what CORBA was able to do, but for the simple tasks required it would be sufficient. Some examples of such tasks might be an application sending a message to the panel saying, "I have started, stop displaying the 'application starting' wait state," or having a new application that starts query to see if any other applications of the same name are running. If they are, simply call a function on the remote application to create a new window, rather than starting a new process. Implementation: --------------- DCOP is a simple IPC/RPC mechanism built to operate over sockets. Either unix domain sockets or tcp/ip sockets are supported. DCOP is built on top of the Inter Client Exchange (ICE) protocol, which comes standard as a part of X11R6 and later. It also depends on Qt, but beyond that it does not require any other libraries. Because of this, it is extremely lightweight, enabling it to be linked into all KDE applications with low overhead. Model: ------ The model is simple. Each application using DCOP is a client. They communicate to each other through a DCOP server, which functions like a traffic director, dispatching messages/calls to the proper destinations. All clients are peers of each other. Two types of actions are possible with DCOP: "send and forget" messages, which do not block, and "calls," which block waiting for some data to be returned. Any data that will be sent is serialized (marshalled, for you CORBA types) using the built-in QDataStream operators available in all of the Qt classes. This is fast and easy. In fact it's so little work that you can easily write the marshalling code by hand. In addition, there's a simple IDL-like compiler available (dcopidl and dcopidl2cpp) that generates stubs and skeletons for you. Using the dcopidl compiler has the additional benefit of type safety. This HOWTO describes the manual method first and covers the dcopidl compiler later. Establishing the Connection: ---------------------------- KApplication has gained a method called "KApplication::dcopClient()" which returns a pointer to a DCOPClient instance. The first time this method is called, the client class will be created. DCOPClients have unique identifiers attached to them which are based on what KApplication::name() returns. In fact, if there is only a single instance of the program running, the appId will be equal to KApplication::name(). To actually enable DCOP communication to begin, you must use DCOPClient::attach(). This will attempt to attach to the DCOP server. If no server is found or there is any other type of error, attach() will return false. KApplication will catch a dcop signal and display an appropriate error message box in that case. After connecting with the server via DCOPClient::attach(), you need to register this appId with the server so it knows about you. Otherwise, you are communicating anonymously. Use the DCOPClient::registerAs(const QCString &name) to do so. In the simple case: /* * returns the appId that is actually registered, which _may_ be * different from what you passed */ appId = client->registerAs(kApp->name()); If you never retrieve the DCOPClient pointer from KApplication, the object will not be created and thus there will be no memory overhead. You may also detach from the server by calling DCOPClient::detach(). If you wish to attach again you will need to re-register as well. If you only wish to change the ID under which you are registered, simply call DCOPClient::registerAs() with the new name. KUniqueApplication automatically registers itself to DCOP. If you are using KUniqueApplication you should not attach or register yourself, this is already done. The appId is by definition equal to kapp->name(). You can retrieve the registered DCOP client by calling kapp->dcopClient(). Sending Data to a Remote Application: ------------------------------------- To actually communicate, you have one of two choices. You may either call the "send" or the "call" method. Both methods require three identification parameters: an application identifier, a remote object, a remote function. Sending is asynchronous (i.e. it returns immediately) and may or may not result in your own application being sent a message at some point in the future. Then "send" requires one and "call" requires two data parameters. The remote object must be specified as an object hierarchy. That is, if the toplevel object is called "fooObject" and has the child "barObject", you would reference this object as "fooObject/barObject". Functions must be described by a full function signature. If the remote function is called "doIt", and it takes an int, it would be described as "doIt(int)". Please note that the return type is not specified here, as it is not part of the function signature (or at least the C++ understanding of a function signature). You will get the return type of a function back as an extra parameter to DCOPClient::call(). See the section on call() for more details. In order to actually get the data to the remote client, it must be "serialized" via a QDataStream operating on a QByteArray. This is how the data parameter is "built". A few examples will make clear how this works. Say you want to call "doIt" as described above, and not block (or wait for a response). You will not receive the return value of the remotely called function, but you will not hang while the RPC is processed either. The return value of send() indicates whether DCOP communication succeeded or not. QByteArray data; QDataStream arg(data, IO_WriteOnly); arg << 5; if (!client->send("someAppId", "fooObject/barObject", "doIt(int)", data)) qDebug("there was some error using DCOP."); OK, now let's say we wanted to get the data back from the remotely called function. You have to execute a call() instead of a send(). The returned value will then be available in the data parameter "reply". The actual return value of call() is still whether or not DCOP communication was successful. QByteArray data, replyData; QCString replyType; QDataStream arg(data, IO_WriteOnly); arg << 5; if (!client->call("someAppId", "fooObject/barObject", "doIt(int)", data, replyType, replyData)) qDebug("there was some error using DCOP."); else { QDataStream reply(replyData, IO_ReadOnly); if (replyType == "QString") { QString result; reply >> result; print("the result is: %s",result.latin1()); } else qDebug("doIt returned an unexpected type of reply!"); } N.B.: You cannot call() a method belonging to an application which has registered with an unique numeric id appended to its textual name (see dcopclient.h for more info). In this case, DCOP would not know which application it should connect with to call the method. This is not an issue with send(), as you can broadcast to all applications that have registered with appname- by using a wildcard (e.g. 'konsole-*'), which will send your signal to all applications called 'konsole'. Receiving Data via DCOP: ------------------------ Currently the only real way to receive data from DCOP is to multiply inherit from the normal class that you are inheriting (usually some sort of QWidget subclass or QObject) as well as the DCOPObject class. DCOPObject provides one very important method: DCOPObject::process(). This is a pure virtual method that you must implement in order to process DCOP messages that you receive. It takes a function signature, QByteArray of parameters, and a reference to a QByteArray for the reply data that you must fill in. Think of DCOPObject::process() as a sort of dispatch agent. In the future, there will probably be a precompiler for your sources to write this method for you. However, until that point you need to examine the incoming function signature and take action accordingly. Here is an example implementation. bool BarObject::process(const QCString &fun, const QByteArray &data, QCString &replyType, QByteArray &replyData) { if (fun == "doIt(int)") { QDataStream arg(data, IO_ReadOnly); int i; // parameter arg >> i; QString result = self->doIt (i); QDataStream reply(replyData, IO_WriteOnly); reply << result; replyType = "QString"; return true; } else { qDebug("unknown function call to BarObject::process()"); return false; } } Receiving Calls and processing them: ------------------------------------ If your applications is able to process incoming function calls right away the above code is all you need. When your application needs to do more complex tasks you might want to do the processing out of 'process' function call and send the result back later when it becomes available. For this you can ask your DCOPClient for a transactionId. You can then return from the 'process' function and when the result is available finish the transaction. In the mean time your application can receive incoming DCOP function calls from other clients. Such code could like this: bool BarObject::process(const QCString &fun, const QByteArray &data, QCString &, QByteArray &) { if (fun == "doIt(int)") { QDataStream arg(data, IO_ReadOnly); int i; // parameter arg >> i; QString result = self->doIt(i); DCOPClientTransaction *myTransaction; myTransaction = kapp->dcopClient()->beginTransaction(); // start processing... // Calls slotProcessingDone when finished. startProcessing( myTransaction, i); return true; } else { qDebug("unknown function call to BarObject::process()"); return false; } } slotProcessingDone(DCOPClientTransaction *myTransaction, const QString &result) { QCString replyType = "QString"; QByteArray replyData; QDataStream reply(replyData, IO_WriteOnly); reply << result; kapp->dcopClient()->endTransaction( myTransaction, replyType, replyData ); } DCOP Signals ------------ Sometimes a component wants to send notifications via DCOP to other components but does not know which components will be interested in these notifications. One could use a broadcast in such a case but this is a very crude method. For a more sophisticated method DCOP signals have been invented. DCOP signals are very similair to Qt signals, there are some differences though. A DCOP signal can be connected to a DCOP function. Whenever the DCOP signal gets emitted, the DCOP functions to which the signal is connected are being called. DCOP signals are, just like Qt signals, one way. They do not provide a return value. A DCOP signal originates from a DCOP Object/DCOP Client combination (sender). It can be connected to a function of another DCOP Object/DCOP Client combination (receiver). There are two major differences between connections of Qt signals and connections of DCOP signals. In DCOP, unlike Qt, a signal connections can have an anonymous sender and, unlike Qt, a DCOP signal connection can be non-volatile. With DCOP one can connect a signal without specifying the sending DCOP Object or DCOP Client. In that case signals from any DCOP Object and/or DCOP Client will be delivered. This allows the specification of certain events without tying oneself to a certain object that implementes the events. Another DCOP feature are so called non-volatile connections. With Qt signal connections, the connection gets deleted when either sender or receiver of the signal gets deleted. A volatile DCOP signal connection will behave the same. However, a non-volatile DCOP signal connection will not get deleted when the sending object gets deleted. Once a new object gets created with the same name as the original sending object, the connection will be restored. There is no difference between the two when the receiving object gets deleted, in that case the signal connection will always be deleted. A receiver can create a non-volatile connection while the sender doesn't (yet) exist. An anonymous DCOP connection should always be non-volatile. The following example shows how KLauncher emits a signal whenever it notices that an application that was started via KLauncher terminates. QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << pid; kapp->dcopClient()->emitDCOPSignal("clientDied(pid_t)", params); The task manager of the KDE panel connects to this signal. It uses an anonymous connection (it doesn't require that the signal is being emitted by KLauncher) that is non-volatile: connectDCOPSignal(0, 0, "clientDied(pid_t)", "clientDied(pid_t)", false); It connects the clientDied(pid_t) signal to its own clientDied(pid_t) DCOP function. In this case the signal and the function to call have the same name. This isn't needed as long as the arguments of both signal and receiving function match. The receiving function may ignore one or more of the trailing arguments of the signal. E.g. it is allowed to connect the clientDied(pid_t) signal to a clientDied(void) DCOP function. Using the dcopidl compiler --------------------- dcopidl makes setting up a DCOP server easy. Instead of having to implement the process() method and unmarshalling (retrieving from QByteArray) parameters manually, you can let dcopidl create the necessary code on your behalf. This also allows you to describe the interface for your class in a single, separate header file. Writing an IDL file is very similar to writing a normal C++ header. An exception is the keyword 'ASYNC'. It indicates that a call to this function shall be processed asynchronously. For the C++ compiler, it expands to 'void'. Example: #ifndef MY_INTERFACE_H #define MY_INTERFACE_H #include class MyInterface : virtual public DCOPObject { K_DCOP k_dcop: virtual ASYNC myAsynchronousMethod(QString someParameter) = 0; virtual QRect mySynchronousMethod() = 0; }; #endif As you can see, you're essentially declaring an abstract base class, which virtually inherits from DCOPObject. If you're using the standard KDE build scripts, then you can simply add this file (which you would call MyInterface.h) to your sources directory. Then you edit your Makefile.am, adding 'MyInterface.skel' to your SOURCES list and MyInterface.h to include_HEADERS. The build scripts will use dcopidl to parse MyInterface.h, converting it to an XML description in MyInterface.kidl. Next, a file called MyInterface_skel.cpp will automatically be created, compiled and linked with your binary. The next thing you have to do is to choose which of your classes will implement the interface described in MyInterface.h. Alter the inheritance of this class such that it virtually inherits from MyInterface. Then add declarations to your class interface similar to those on MyInterface.h, but virtual, not pure virtual. Example: class MyClass: public QObject, virtual public MyInterface { Q_OBJECT public: MyClass(); ~MyClass(); ASYNC myAsynchronousMethod(QString someParameter); QRect mySynchronousMethod(); }; Note: (Qt issue) Remember that if you are inheriting from QObject, you must place it first in the list of inherited classes. In the implementation of your class' ctor, you must explicitly initialize those classes from which you are inheriting from. This is, of course, good practise, but it is essential here as you need to tell DCOPObject the name of the interface which your are implementing. Example: MyClass::MyClass() : QObject(), DCOPObject("MyInterface") { // whatever... } Now you can simply implement the methods you have declared in your interface, exactly the same as you would normally. Example: void MyClass::myAsynchronousMethod(QString someParameter) { qDebug("myAsyncMethod called with param `" + someParameter + "'"); } It is not necessary (though very clean) to define an interface as an abstract class of its own, like we did in the example above. We could just as well have defined a k_dcop section directly within MyClass: class MyClass: public QObject, virtual public DCOPObject { Q_OBJECT K_DCOP public: MyClass(); ~MyClass(); k_dcop: ASYNC myAsynchronousMethod(QString someParameter); QRect mySynchronousMethod(); }; In addition to skeletons, dcopidl2cpp also generate stubs. Those make it easy to call a DCOP interface without doing the marshalling manually. To use a stub, add MyInterface.stub to the SOURCES list of your Makefile.am. The stub class will then be called MyInterface_stub. Conclusion: ----------- Hopefully this document will get you well on your way into the world of inter-process communication with KDE! Please direct all comments and/or suggestions to Preston Brown and Matthias Ettrich . Inter-user communication ------------------------ Sometimes it might be interesting to use DCOP between processes belonging to different users, e.g. a frontend process running with the user's id, and a backend process running as root. To do this, two steps have to be taken: a) both processes need to talk to the same DCOP server b) the authentication must be ensured For the first step, you simply pass the server address (as found in .DCOPserver) to the second process. For the authentication, you can use the ICEAUTHORITY environment variable to tell the second process where to find the authentication information. (Note that this implies that the second process is able to read the authentication file, so it will probably only work if the second process runs as root. If it should run as another user, a similar approach to what kdesu does with xauth must be taken. In fact, it would be a very good idea to add DCOP support to kdesu!) For example ICEAUTHORITY=~user/.ICEauthority kdesu root -c kcmroot -dcopserver `cat ~user/.DCOPserver` will, after kdesu got the root password, execute kcmroot as root, talking to the user's dcop server. NOTE: DCOP communication is not encrypted, so please do not pass important information around this way. Performance Tests: ------------------ A few back-of-the-napkin tests folks: Code: #include int main(int argc, char **argv) { KApplication *app; app = new KApplication(argc, argv, "testit"); return app->exec(); } Compiled with: g++ -O2 -o testit testit.cpp -I$QTDIR/include -L$QTDIR/lib -lkdecore on Linux yields the following memory use statistics: VmSize: 8076 kB VmLck: 0 kB VmRSS: 4532 kB VmData: 208 kB VmStk: 20 kB VmExe: 4 kB VmLib: 6588 kB If I create the KApplication's DCOPClient, and call attach() and registerAs(), it changes to this: VmSize: 8080 kB VmLck: 0 kB VmRSS: 4624 kB VmData: 208 kB VmStk: 20 kB VmExe: 4 kB VmLib: 6588 kB Basically it appears that using DCOP causes 100k more memory to be resident, but no more data or stack. So this will be shared between all processes, right? 100k to enable DCOP in all apps doesn't seem bad at all. :) OK now for some timings. Just creating a KApplication and then exiting (i.e. removing the call to KApplication::exec) takes this much time: 0.28user 0.02system 0:00.32elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (1084major+62minor)pagefaults 0swaps I.e. about 1/3 of a second on my PII-233. Now, if we create our DCOP object and attach to the server, it takes this long: 0.27user 0.03system 0:00.34elapsed 87%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (1107major+65minor)pagefaults 0swaps I.e. about 1/3 of a second. Basically DCOPClient creation and attaching gets lost in the statistical variation ("noise"). I was getting times between .32 and .48 over several runs for both of the example programs, so obviously system load is more relevant than the extra two calls to DCOPClient::attach and DCOPClient::registerAs, as well as the actual DCOPClient constructor time. dbus-1.10.6/doc/dbus-api-design.duck0000644000175000017500000011630312602773110017131 0ustar00smcvsmcv00000000000000= D-Bus API Design Guidelines @link[guide >index] @credit[type="author copyright"] @name Philip Withnall @email philip.withnall@collabora.co.uk @years 2015 @desc Guidelines for writing high quality D-Bus APIs @revision[date=2015-02-05 status=draft] [synopsis] [title] Summary The most common use for D-Bus is in implementing a service which will be consumed by multiple client programs, and hence all interfaces exported on the bus form a public API. Designing a D-Bus API is like designing any other API: there is a lot of flexibility, but there are design patterns to follow and anti-patterns to avoid. This guide aims to explain the best practices for writing D-Bus APIs. These have been refined over several years of use of D-Bus in many projects. Pointers will be given for implementing APIs using common D-Bus libraries like $link[>>https://developer.gnome.org/gio/stable/gdbus-convenience.html](GDBus), but detailed implementation instructions are left to the libraries’ documentation. Note that you should $em(not) use dbus-glib to implement D-Bus services as it is deprecated and unmaintained. Most services should also avoid libdbus (dbus-1), which is a low-level library and is awkward to use correctly: it is designed to be used via a language binding such as $link[>>http://qt-project.org/doc/qt-4.8/qtdbus.html](QtDBus). For documentation on D-Bus itself, see the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html](D-Bus specification). [links section] == APIs [id="apis"] A D-Bus API is a specification of one or more interfaces, which will be implemented by objects exposed by a service on the bus. Typically an API is designed as a set of $link[>#interface-files](interface files), and the implementation of the service follows those files. Some projects, however, choose to define the API in the code for the service, and to export XML interface files from the running service $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable](using D-Bus introspection). Both are valid approaches. For simplicity, this document uses the XML descriptions of D-Bus interfaces as the canonical representation. == Interface files [id="interface-files"] A D-Bus interface file is an XML file which describes one or more D-Bus interfaces, and is the best way of describing a D-Bus API in a machine readable way. The format is described in the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus specification), and is supported by tools such as $cmd(gdbus-codegen). Interface files for public API should be installed to $code($var($$(datadir$))/dbus-1/interfaces) so that other services can load them. Private APIs should not be installed. There should be one file installed per D-Bus interface, named after the interface, containing a single top-level $code() element with a single $code() beneath it. For example, interface $code(com.example.MyService1.Manager) would be described by file $file($var($$(datadir$))/dbus-1/interfaces/com.example.MyService1.Manager.xml): [listing] [title] Example D-Bus Interface XML [desc] A brief example interface XML document. [code mime="application/xml"] Name of new contact E-mail address of new contact ID of newly added contact Adds a new contact to the address book with their name and e-mail address. If an interface defined by service A needs to be used by client B, client B should declare a build time dependency on service A, and use the installed copy of the interface file for any code generation it has to do. It should $em(not) have a local copy of the interface, as that could then go out of sync with the canonical copy in service A’s git repository. == API versioning [id="api-versioning"] $link[>>http://ometer.com/parallel.html](Just like C APIs), D-Bus interfaces should be designed to be usable in parallel with API-incompatible versions. This is achieved by including a version number in each interface name, service name and object path which is incremented on every backwards-incompatible change. Version numbers should be included in all APIs from the first release, as that means moving to a new version is as simple as incrementing the number, rather than inserting a number everywhere, which takes more effort. New API can be added to a D-Bus interface without incrementing the version number, as such additions are still backwards-compatible. However, clients should gracefully handle the $code(org.freedesktop.DBus.Error.UnknownMethod) error reply from all D-Bus method calls if they want to run against older versions of the service which don’t implement new methods. (This also prevents use of generated bindings; any method which a client wants to gracefully fall back from should be called using a generic D-Bus method invocation rather than a specific generated binding.) When API is broken, changed or removed, the service’s version number must be bumped; for example, from $code(com.example.MyService1) to $code(com.example.MyService2). If backwards compatibility is maintained in the service by implementing both the old and new interfaces, the service can own $em(both) well-known names and clients can use whichever they support. As discussed in $link[>#annotations], new or deprecated APIs should be marked in the interface XML using annotations. Note, however, that supporting multiple interface versions simultaneously requires that $em(object paths) are versioned as well, so objects $em(must not) be put on the bus at the root path (‘/’). This is for technical reasons: signals sent from a D-Bus service have the originating service name overwritten by its unique name (e.g. $code(com.example.MyService2) is overwritten by $code(:1:15)). If object paths are shared between objects implementing two versions of the service’s interface, client programs cannot tell which object a signal has come from. The solution is to include the version number in all object paths, for example $code(/com/example/MyService1/Manager) instead of $code(/) or $code(/com/example/MyService/Manager). In summary, version numbers should be included in all service names, interface names and object paths: [list] * $code(com.example.MyService1) * $code(com.example.MyService1.InterestingInterface) * $code(com.example.MyService1.OtherInterface) * $code(/com/example/MyService1/Manager) * $code(/com/example/MyService1/OtherObject) == API design [id="api-design"] D-Bus API design is broadly the same as C API design, but there are a few additional points to bear in mind which arise both from D-Bus’ features (explicit errors, signals and properties), and from its implementation as an IPC system. D-Bus method calls are much more expensive than C function calls, typically taking on the order of milliseconds to complete a round trip. Therefore, the design should minimize the number of method calls needed to perform an operation. The type system is very expressive, especially compared to C’s, and APIs should take full advantage of it. Similarly, its support for signals and properties differentiates it from normal C APIs, and well written D-Bus APIs make full use of these features where appropriate. They can be coupled with standard interfaces defined in the D-Bus specification to allow for consistent access to properties and objects in a hierarchy. === Minimizing Round Trips [id="round-trips"] Each D-Bus method call is a round trip from a client program to a service and back again, which is expensive — taking on the order of a millisecond. One of the top priorities in D-Bus API design is to minimize the number of round trips needed by clients. This can be achieved by a combination of providing specific convenience APIs and designing APIs which operate on large data sets in a single call, rather than requiring as many calls as elements in the data set. Consider an address book API, $code(com.example.MyService1.AddressBook). It might have an $code(AddContact(ss$) → (u$)) method to add a contact (taking name and e-mail address parameters and returning a unique contact ID), and a $code(RemoveContact(u$)) method to remove one by ID. In the normal case of operating on single contacts in the address book, these calls are optimal. However, if the user wants to import a list of contacts, or delete multiple contacts simultaneously, one call has to be made per contact — this could take a long time for large contact lists. Instead of the $code(AddContact) and $code(RemoveContact) methods, the interface could have an $code(UpdateContacts(a(ss$)au$) → (au$)) method, which takes an array of structs containing the new contacts’ details, and an array of IDs of the contacts to delete, and returns an array of IDs for the new contacts. This reduces the number of round trips needed to one. Adding convenience APIs to replace a series of common method calls with a single method call specifically for that task is best done after the API has been profiled and bottlenecks identified, otherwise it could lead to premature optimization. One area where convenience methods can typically be added is during initialization of a client, where multiple method calls are needed to establish its state with the service. === Taking Advantage of the Type System [id="type-system"] D-Bus’ type system is similar to Python’s, but with a terser syntax which may be unfamiliar to C developers. The key to using the type system effectively is to expose as much structure in types as possible. In particular, sending structured strings over D-Bus should be avoided, as they need to be built and parsed; both are complex operations which are prone to bugs. For APIs being used in constrained situations, enumerated values should be transmitted as unsigned integers. For APIs which need to be extended by third parties or which are used in more loosely coupled systems, enumerated values should be strings in some defined format. Transmitting values as integers means string parsing and matching can be avoided, the messages are more compact, and typos can be more easily avoided by developers (if, for example, C enums are used in the implementation). Transmitting values as strings means additional values can be defined by third parties without fear of conflicting over integer values; for instance by using the same reverse-domain-name namespacing as D-Bus interfaces. In both cases, the interface documentation should describe the meaning of each value. It should state whether the type can be extended in future and, if so, how the service and client should handle unrecognized values — typically by considering them equal to an ‘unknown’ or ‘failure’ value. Conventionally, zero is used as the ‘unknown’ value. [example] For example, instead of: [code style="invalid" mime="application/xml"] Use: [code style="valid" mime="application/xml"] Similarly, enumerated values should be used instead of booleans, as they allow extra values to be added in future, and there is no ambiguity about the sense of the boolean value. [example] For example, instead of: [code style="invalid" mime="application/xml"] Be more explicit than a boolean: [code style="valid" mime="application/xml"] Enumerated values should also be used instead of $em(human readable) strings, which should not be sent over the bus if possible. The service and client could be running in different locales, and hence interpret any human readable strings differently, or present them to the user in the wrong language. Transmit an enumerated value and convert it to a human readable string in the client. In situations where a service has received a human readable string from somewhere else, it should pass it on unmodified to the client, ideally with its locale alongside. Passing human readable information to a client is better than passing nothing. [example] For example, instead of: [code style="invalid" mime="application/xml"] The progress should be reported as an enumerated value: [code style="valid" mime="application/xml"] D-Bus has none of the problems of signed versus unsigned integers which C has (specifically, it does not do implicit sign conversion), so integer types should always be chosen to be an appropriate size and signedness for the data they could possibly contain. Typically, unsigned values are more frequently needed than signed values. Structures can be used almost anywhere in a D-Bus type, and arrays of structures are particularly useful. Structures should be used wherever data fields are related. Note, however, that structures are not extensible in future, so always consider $link[>#extensibility]. [example] For example, instead of several identically-indexed arrays containing different properties of the same set of items: [code style="invalid" mime="application/xml"] The arrays can be combined into a single array of structures: [code style="invalid" mime="application/xml"] Note that D-Bus arrays are automatically transmitted with their length, so there is no need to null-terminate them or encode their length separately. [comment] FIXME: Mention maybe types and the extended kdbus/GVariant type system once that’s stable and round-trip-ability is no longer a concern. === Extensibility [id="extensibility"] Some D-Bus APIs have very well-defined use cases, and will never need extension. Others are used in more loosely coupled systems which may change over time, and hence should be designed to be extensible from the beginning without the need to break API in future. This is a trade off between having a more complex API, and being able to easily extend it in future. The key tool for extensibility in D-Bus is $code(a{sv}), the dictionary mapping strings to variants. If well-defined namespaced strings are used as the dictionary keys, arbitrary D-Bus peers can add whatever information they need into the dictionary. Any other peer which understands it can query and retrieve the information; other peers will ignore it. The canonical example of an extensible API using $code(a{sv}) is $link[>>http://telepathy.freedesktop.org/spec/](Telepathy). It uses $code(a{sv}) values as the final element in structures to allow them to be extended in future. A secondary tool is the use of flag fields in method calls. The set of accepted flags is entirely under the control of the interface designer and, as with enumerated types, can be extended in future without breaking API. Adding more flags allows the functionality of the method call to be tweaked. === Using Signals, Properties and Errors [id="using-the-features"] D-Bus method calls are explicitly asynchronous due to the latency inherent in IPC. This means that peers should not block on receiving a reply from a method call; they should schedule other work (in a main loop) and handle the reply when it is received. Even though method replies may take a while, the caller is $em(guaranteed) to receive exactly one reply eventually. This reply could be the return value from the method, an error from the method, or an error from the D-Bus daemon indicating the service failed in some way (e.g. due to crashing). Because of this, service implementations should be careful to always reply exactly once to each method call. Replying at the end of a long-running operation is correct — the client will patiently wait until the operation has finished and the reply is received. Note that D-Bus client bindings may implement synthetic timeouts of several tens of seconds, unless explicitly disabled for a call. For very long-running operations, you should disable the client bindings’ timeout and make it clear in the client’s UI that the application has not frozen and is simply running a long operation. An anti-pattern to avoid in this situation is to start a long-running operation when a method call is received, then to never reply to the method call and instead notify the client of completion of the operation via a signal. This approach is incorrect as signal emissions do not have a one-to-one relationship with method calls — the signal could theoretically be emitted multiple times, or never, which the client would not be able to handle. Similarly, use a D-Bus error reply to signify failure of an operation triggered by a method call, rather than using a custom error code in the method’s reply. This means that a reply always indicates success, and an error always indicates failure — rather than a reply indicating either depending on its parameters, and having to return dummy values in the other parameters. Using D-Bus error replies also means such failures can be highlighted in debugging tools, simplifying debugging. Clients should handle all possible standard and documented D-Bus errors for each method call. IPC inherently has more potential failures than normal C function calls, and clients should be prepared to handle all of them gracefully. === Using Standard Interfaces [id="standard-interfaces"] Use standard D-Bus interfaces where possible. ==== Properties [id="interface-properties"] The D-Bus specification defines the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties]($code(org.freedesktop.DBus.Properties)) interface, which should be used by all objects to notify clients of changes to their property values, with the $code(PropertiesChanged) signal. This signal eliminates the need for individual $code($var(PropertyName)Changed) signals, and allows multiple properties to be notified in a single signal emission, reducing IPC round trips. Similarly, the $code(Get) and $code(Set) methods can be used to manipulate properties on an object, eliminating redundant $code(Get$var(PropertyName)) and $code(Set$var(PropertyName)) methods. [example] For example, consider an object implementing an interface $code(com.example.MyService1.SomeInterface) with methods: [list] * $code(GetName($) → (s$)) * $code(SetName(s$) → ($)) * $code(GetStatus($) → (u$)) * $code(RunOperation(ss$) → (u$)) and signals: [list] * $code(NameChanged(u$)) * $code(StatusChanged(u$)) The interface could be cut down to a single method: [list] * $code(RunOperation(ss$) → (u$)) The object could then implement the $code(org.freedesktop.DBus.Properties) interface and define properties: [list] * $code(Name) of type $code(s), read–write * $code(Status) of type $code(u), read-only The $code(NameChanged) and $code(StatusChanged) signals would be replaced by $code(org.freedesktop.DBus.Properties.PropertiesChanged). ==== Object Manager [id="interface-object-manager"] The specification also defines the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager]($code(org.freedesktop.DBus.ObjectManager)) interface, which should be used whenever a service needs to expose a variable number of objects of the same class in a flat or tree-like structure, and clients are expected to be interested in most or all of the objects. For example, this could be used by an address book service which exposes multiple address books, each as a separate object. The $code(GetManagedObjects) method allows the full object tree to be queried, returning all the objects’ properties too, eliminating the need for further IPC round trips to query the properties. If clients are not expected to be interested in most of the exposed objects, $code(ObjectManager) should $em(not) be used, as it will send all of the objects to each client anyway, wasting bus bandwidth. A file manager, therefore, should not expose the entire file system hierarchy using $code(ObjectManager). [example] For example, consider an object implementing an interface $code(com.example.MyService1.AddressBookManager) with methods: [list] * $code(GetAddressBooks($) → (ao$)) and signals: [list] * $code(AddressBookAdded(o$)) * $code(AddressBookRemoved(o$)) If the manager object is at path $code(/com/example/MyService1/AddressBookManager), each address book is a child object, e.g. $code(/com/example/MyService1/AddressBookManager/SomeAddressBook). The interface could be eliminated, and the $code(org.freedesktop.DBus.ObjectManager) interface implemented on the manager object instead. Calls to $code(GetAddressBooks) would become calls to $code(GetManagedObjects) and emissions of the $code(AddressBookAdded) and $code(AddressBookRemoved) signals would become emissions of $code(InterfacesAdded) and $code(InterfacesRemoved). === Naming Conventions [id="naming-conventions"] All D-Bus names, from service names through to method parameters, follow a set of conventions. Following these conventions makes APIs more natural to use and consistent with all other services on the system. Services use reverse-domain-name notation, based on the domain name of the project providing the service (all in lower case), plus a unique name for the service (in camel case). [example] For example, version 2 of an address book application called $code(ContactDex) provided by a software vendor whose website is $code(chocolateteapot.com) would use service name $code(com.chocolateteapot.ContactDex2). Almost all names use camel case with no underscores, as in the examples below. Method and signal parameters are an exception, using $code(lowercase_with_underscores). Type information is never encoded in the parameter name (i.e. $em(not) $link[>>http://en.wikipedia.org/wiki/Hungarian_notation](Hungarian notation)). [example] [terms] - Service Name * $code(com.example.MyService1) - Interface Name * $code(com.example.MyService1.SomeInterface) - Object Path (Root Object) * $code(/com/example/MyService1) - Object Path (Child Object) * $code(/com/example/MyService1/SomeChild) - Object Path (Grandchild Object) * $code(/com/example/MyService1/AnotherChild/Grandchild1) - Method Name * $code(com.example.MyService1.SomeInterface.MethodName) - Signal Name * $code(com.example.MyService1.SomeInterface.SignalName) - Property Name * $code(com.example.MyService1.SomeInterface.PropertyName) See also: $link[>#api-versioning]. == Code generation [id="code-generation"] Rather than manually implementing both the server and client sides of a D-Bus interface, it is often easier to write the interface XML description and use a tool such as $link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)) to generate type-safe C APIs, then build the implementation using those. This avoids the tedious and error-prone process of writing code to build and read D-Bus parameter variants for each method call. Use of code generators is beyond the scope of this guide; for more information, see the $link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen) manual). == Annotations [id="annotations"] Annotations may be added to the interface XML to expose metadata on the API which can be used by documentation or code generation tools to modify their output. Some standard annotations are given in the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus specification), but further annotations may be defined by specific tools. For example, $cmd(gdbus-codegen) defines several useful annotations, listed on its man page. The following annotations are the most useful: [terms] - $code(org.freedesktop.DBus.Deprecated) * Mark a symbol as deprecated. This should be used whenever the API is changed, specifying the version introducing the deprecation, the reason for deprecation, and a replacement symbol to use. - $code(org.gtk.GDBus.Since) * Mark a symbol as having been added to the API after the initial release. This should include the version the symbol was first added in. - $code(org.gtk.GDBus.C.Name) and $code(org.freedesktop.DBus.GLib.CSymbol) * Both used interchangeably to hint at a C function name to use when generating code for a symbol. Use of this annotation can make generated bindings a lot more pleasant to use. - $code(org.freedesktop.DBus.Property.EmitsChangedSignal) * Indicate whether a property is expected to emit change signals. This can affect code generation, but is also useful documentation, as client programs then know when to expect property change notifications and when they have to requery. == Documentation [id="documentation"] Also just like C APIs, D-Bus APIs must be documented. There are several methods for documenting the interfaces, methods, properties and signals in a D-Bus interface XML file, each unfortunately with their own downsides. You should choose the method which best matches the tooling and workflow you are using. === XML Comments XML comments containing documentation in the $link[>>https://developer.gnome.org/gtk-doc-manual/stable/documenting_syntax.html.en](gtk-doc format) is the recommended format for use with $link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)). Using $cmd(gdbus-codegen), these comments can be extracted, converted to DocBook format and included in the project’s API manual. For example: [listing] [title] Documentation Comments in D-Bus Interface XML [desc] Example gtk-doc–style documentation comments in the introspection XML for the $code(org.freedesktop.DBus.Properties) interface. [code mime="application/xml"] [comment] FIXME: This is only present to fix $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2]. === XML Annotations Documentation can also be added as annotation elements in the XML. This format is also supported by $cmd(gdbus-codegen), but gtk-doc comments are preferred. For example: [listing] [title] Documentation Annotations in D-Bus Interface XML [desc] Example GDBus documentation annotations in the introspection XML for the $code(org.freedesktop.DBus.Properties) interface. [code mime="application/xml"] [comment] FIXME: This is only present to fix $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2]. == Service files [id="service-files"] Each D-Bus service must install a $file(.service) file describing its service name and the command to run to start the service. This allows for service activation (see the $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services](D-Bus specification)). Service files must be named after the service’s well-known name, for example file $file(com.example.MyService1.service) for well-known name $code(com.example.MyService1). Files must be installed in $file($var($$(datadir$))/dbus-1/services) for the session bus and $file($var($$(datadir$))/dbus-1/system-services) for the system bus. Note, however, that services on the system bus almost always need a $link[>#security-policies](security policy) as well. == Security Policies [id="security-policies"] At a high level, the D-Bus security model is: [list] * There is a system bus, and zero or more session buses. * Any process may connect to the system bus. The system bus limits which can own names or send method calls, and only processes running as privileged users can receive unicast messages not addressed to them. Every process may receive broadcasts. * Each session bus has an owner (a user). Only its owner may connect; on general-purpose Linux, a session bus is not treated as a privilege boundary, so there is no further privilege separation between processes on it. Full coverage of securing D-Bus services is beyond the scope of this guide, however there are some steps which you can take when designing an API to ease security policy implementation. D-Bus security policies are written as XML files in $file($var($$(sysconfdir$)/dbus-1/system.d)) and $file($var($$(sysconfdir$)/dbus-1/session.d)) and use an allow/deny model, where each message (method call, signal emission, etc.) can be allowed or denied according to the sum of all policy rules which match it. Each $code() or $code() rule in the policy should have the $code(own), $code(send_destination) or $code(receive_sender) attribute set. When designing an API, bear in mind the need to write and install such a security policy, and consider splitting up methods or providing more restricted versions which accept constrained parameters, so that they can be exposed with less restrictive security policies if needed by less trusted clients. Secondly, the default D-Bus security policy for the system bus is restrictive enough to allow sensitive data, such as passwords, to be safely sent over the bus in unicast messages (including unicast signals); so there is no need to complicate APIs by implementing extra security. Note, however, that sensitive data must $em(not) be sent in broadcast signals, as they can be seen by all peers on the bus. The default policy for the session bus is not restrictive, but it is typically not a security boundary. == Debugging [id="debugging"] Debugging services running on D-Bus can be tricky, especially if they are launched via service activation and hence in an environment out of your control. Three main tools are available: D-Bus Monitor, Bustle and D-Feet. === D-Bus Monitor [id="dbus-monitor"] $link[>>http://dbus.freedesktop.org/doc/dbus-monitor.1.html]($cmd(dbus-monitor)) is a core D-Bus tool, and allows eavesdropping on the session or system bus, printing all messages it sees. The messages may be filtered using a standard $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules](D-Bus match rule) to make the stream more manageable. Previous versions of D-Bus have required the security policy for the system bus to be manually relaxed to allow eavesdropping on all messages. This meant that debugging it was difficult and insecure. The latest versions of D-Bus add support for monitor-only connections for the root user, which means that $cmd(dbus-monitor) can be run as root to painlessly monitor all messages on the system bus without modifying its security policy. === Bustle [id="bustle"] $link[>>http://willthompson.co.uk/bustle/](Bustle) is a graphical version of $cmd(dbus-monitor), with a UI focused on profiling D-Bus performance by plotting messages on a timeline. It is ideal for finding bottlenecks in IPC performance between a service and client. === D-Feet [id="d-feet"] $link[>>https://wiki.gnome.org/Apps/DFeet](D-Feet) is an introspection tool for D-Bus, which displays all peers on the bus graphically, with their objects, interfaces, methods, signals and properties listed for examination. It is useful for debugging all kinds of issues related to presence of services on the bus and the objects they expose. dbus-1.10.6/doc/dbus-tutorial.xml0000644000175000017500000007531412602773110016634 0ustar00smcvsmcv00000000000000
    D-Bus Tutorial Version 0.5.0 20 August 2006 Havoc Pennington Red Hat, Inc.
    hp@pobox.com
    David Wheeler John Palmieri Red Hat, Inc.
    johnp@redhat.com
    Colin Walters Red Hat, Inc.
    walters@redhat.com
    Tutorial Work In Progress This tutorial is not complete; it probably contains some useful information, but also has plenty of gaps. Right now, you'll also need to refer to the D-Bus specification, Doxygen reference documentation, and look at some examples of how other apps use D-Bus. Enhancing the tutorial is definitely encouraged - send your patches or suggestions to the mailing list. If you create a D-Bus binding, please add a section to the tutorial for your binding, if only a short section with a couple of examples. What is D-Bus? D-Bus is a system for interprocess communication (IPC). Architecturally, it has several layers: A library, libdbus, that allows two applications to connect to each other and exchange messages. A message bus daemon executable, built on libdbus, that multiple applications can connect to. The daemon can route messages from one application to zero or more other applications. Wrapper libraries or bindings based on particular application frameworks. For example, libdbus-glib and libdbus-qt. There are also bindings to languages such as Python. These wrapper libraries are the API most people should use, as they simplify the details of D-Bus programming. libdbus is intended to be a low-level backend for the higher level bindings. Much of the libdbus API is only useful for binding implementation. libdbus only supports one-to-one connections, just like a raw network socket. However, rather than sending byte streams over the connection, you send messages. Messages have a header identifying the kind of message, and a body containing a data payload. libdbus also abstracts the exact transport used (sockets vs. whatever else), and handles details such as authentication. The message bus daemon forms the hub of a wheel. Each spoke of the wheel is a one-to-one connection to an application using libdbus. An application sends a message to the bus daemon over its spoke, and the bus daemon forwards the message to other connected applications as appropriate. Think of the daemon as a router. The bus daemon has multiple instances on a typical computer. The first instance is a machine-global singleton, that is, a system daemon similar to sendmail or Apache. This instance has heavy security restrictions on what messages it will accept, and is used for systemwide communication. The other instances are created one per user login session. These instances allow applications in the user's session to communicate with one another. The systemwide and per-user daemons are separate. Normal within-session IPC does not involve the systemwide message bus process and vice versa. D-Bus applications There are many, many technologies in the world that have "Inter-process communication" or "networking" in their stated purpose: CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE), and probably hundreds more. Each of these is tailored for particular kinds of application. D-Bus is designed for two specific cases: Communication between desktop applications in the same desktop session; to allow integration of the desktop session as a whole, and address issues of process lifecycle (when do desktop components start and stop running). Communication between the desktop session and the operating system, where the operating system would typically include the kernel and any system daemons or processes. For the within-desktop-session use case, the GNOME and KDE desktops have significant previous experience with different IPC solutions such as CORBA and DCOP. D-Bus is built on that experience and carefully tailored to meet the needs of these desktop projects in particular. D-Bus may or may not be appropriate for other applications; the FAQ has some comparisons to other IPC systems. The problem solved by the systemwide or communication-with-the-OS case is explained well by the following text from the Linux Hotplug project:
    A gap in current Linux support is that policies with any sort of dynamic "interact with user" component aren't currently supported. For example, that's often needed the first time a network adapter or printer is connected, and to determine appropriate places to mount disk drives. It would seem that such actions could be supported for any case where a responsible human can be identified: single user workstations, or any system which is remotely administered. This is a classic "remote sysadmin" problem, where in this case hotplugging needs to deliver an event from one security domain (operating system kernel, in this case) to another (desktop for logged-in user, or remote sysadmin). Any effective response must go the other way: the remote domain taking some action that lets the kernel expose the desired device capabilities. (The action can often be taken asynchronously, for example letting new hardware be idle until a meeting finishes.) At this writing, Linux doesn't have widely adopted solutions to such problems. However, the new D-Bus work may begin to solve that problem.
    D-Bus may happen to be useful for purposes other than the one it was designed for. Its general properties that distinguish it from other forms of IPC are: Binary protocol designed to be used asynchronously (similar in spirit to the X Window System protocol). Stateful, reliable connections held open over time. The message bus is a daemon, not a "swarm" or distributed architecture. Many implementation and deployment issues are specified rather than left ambiguous/configurable/pluggable. Semantics are similar to the existing DCOP system, allowing KDE to adopt it more easily. Security features to support the systemwide mode of the message bus.
    Concepts Some basic concepts apply no matter what application framework you're using to write a D-Bus application. The exact code you write will be different for GLib vs. Qt vs. Python applications, however. Here is a diagram (png svg) that may help you visualize the concepts that follow. Native Objects and Object Paths Your programming framework probably defines what an "object" is like; usually with a base class. For example: java.lang.Object, GObject, QObject, python's base Object, or whatever. Let's call this a native object. The low-level D-Bus protocol, and corresponding libdbus API, does not care about native objects. However, it provides a concept called an object path. The idea of an object path is that higher-level bindings can name native object instances, and allow remote applications to refer to them. The object path looks like a filesystem path, for example an object could be named /org/kde/kspread/sheets/3/cells/4/5. Human-readable paths are nice, but you are free to create an object named /com/mycompany/c5yo817y0c1y1c5b if it makes sense for your application. Namespacing object paths is smart, by starting them with the components of a domain name you own (e.g. /org/kde). This keeps different code modules in the same process from stepping on one another's toes. Methods and Signals Each object has members; the two kinds of member are methods and signals. Methods are operations that can be invoked on an object, with optional input (aka arguments or "in parameters") and output (aka return values or "out parameters"). Signals are broadcasts from the object to any interested observers of the object; signals may contain a data payload. Both methods and signals are referred to by name, such as "Frobate" or "OnClicked". Interfaces Each object supports one or more interfaces. Think of an interface as a named group of methods and signals, just as it is in GLib or Qt or Java. Interfaces define the type of an object instance. DBus identifies interfaces with a simple namespaced string, something like org.freedesktop.Introspectable. Most bindings will map these interface names directly to the appropriate programming language construct, for example to Java interfaces or C++ pure virtual classes. Proxies A proxy object is a convenient native object created to represent a remote object in another process. The low-level DBus API involves manually creating a method call message, sending it, then manually receiving and processing the method reply message. Higher-level bindings provide proxies as an alternative. Proxies look like a normal native object; but when you invoke a method on the proxy object, the binding converts it into a DBus method call message, waits for the reply message, unpacks the return value, and returns it from the native method.. In pseudocode, programming without proxies might look like this: Message message = new Message("/remote/object/path", "MethodName", arg1, arg2); Connection connection = getBusConnection(); connection.send(message); Message reply = connection.waitForReply(message); if (reply.isError()) { } else { Object returnValue = reply.getReturnValue(); } Programming with proxies might look like this: Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path"); Object returnValue = proxy.MethodName(arg1, arg2); Bus Names When each application connects to the bus daemon, the daemon immediately assigns it a name, called the unique connection name. A unique name begins with a ':' (colon) character. These names are never reused during the lifetime of the bus daemon - that is, you know a given name will always refer to the same application. An example of a unique name might be :34-907. The numbers after the colon have no meaning other than their uniqueness. When a name is mapped to a particular application's connection, that application is said to own that name. Applications may ask to own additional well-known names. For example, you could write a specification to define a name called com.mycompany.TextEditor. Your definition could specify that to own this name, an application should have an object at the path /com/mycompany/TextFileManager supporting the interface org.freedesktop.FileHandler. Applications could then send messages to this bus name, object, and interface to execute method calls. You could think of the unique names as IP addresses, and the well-known names as domain names. So com.mycompany.TextEditor might map to something like :34-907 just as mycompany.com maps to something like 192.168.0.5. Names have a second important use, other than routing messages. They are used to track lifecycle. When an application exits (or crashes), its connection to the message bus will be closed by the operating system kernel. The message bus then sends out notification messages telling remaining applications that the application's names have lost their owner. By tracking these notifications, your application can reliably monitor the lifetime of other applications. Bus names can also be used to coordinate single-instance applications. If you want to be sure only one com.mycompany.TextEditor application is running for example, have the text editor application exit if the bus name already has an owner. Addresses Applications using D-Bus are either servers or clients. A server listens for incoming connections; a client connects to a server. Once the connection is established, it is a symmetric flow of messages; the client-server distinction only matters when setting up the connection. If you're using the bus daemon, as you probably are, your application will be a client of the bus daemon. That is, the bus daemon listens for connections and your application initiates a connection to the bus daemon. A D-Bus address specifies where a server will listen, and where a client will connect. For example, the address unix:path=/tmp/abcdef specifies that the server will listen on a UNIX domain socket at the path /tmp/abcdef and the client will connect to that socket. An address can also specify TCP/IP sockets, or any other transport defined in future iterations of the D-Bus specification. When using D-Bus with a message bus daemon, libdbus automatically discovers the address of the per-session bus daemon by reading an environment variable. It discovers the systemwide bus daemon by checking a well-known UNIX domain socket path (though you can override this address with an environment variable). If you're using D-Bus without a bus daemon, it's up to you to define which application will be the server and which will be the client, and specify a mechanism for them to agree on the server's address. This is an unusual case. Big Conceptual Picture Pulling all these concepts together, to specify a particular method call on a particular object instance, a number of nested components have to be named: Address -> [Bus Name] -> Path -> Interface -> Method The bus name is in brackets to indicate that it's optional -- you only provide a name to route the method call to the right application when using the bus daemon. If you have a direct connection to another application, bus names aren't used; there's no bus daemon. The interface is also optional, primarily for historical reasons; DCOP does not require specifying the interface, instead simply forbidding duplicate method names on the same object instance. D-Bus will thus let you omit the interface, but if your method name is ambiguous it is undefined which method will be invoked. Messages - Behind the Scenes D-Bus works by sending messages between processes. If you're using a sufficiently high-level binding, you may never work with messages directly. There are 4 message types: Method call messages ask to invoke a method on an object. Method return messages return the results of invoking a method. Error messages return an exception caused by invoking a method. Signal messages are notifications that a given signal has been emitted (that an event has occurred). You could also think of these as "event" messages. A method call maps very simply to messages: you send a method call message, and receive either a method return message or an error message in reply. Each message has a header, including fields, and a body, including arguments. You can think of the header as the routing information for the message, and the body as the payload. Header fields might include the sender bus name, destination bus name, method or signal name, and so forth. One of the header fields is a type signature describing the values found in the body. For example, the letter "i" means "32-bit integer" so the signature "ii" means the payload has two 32-bit integers. Calling a Method - Behind the Scenes A method call in DBus consists of two messages; a method call message sent from process A to process B, and a matching method reply message sent from process B to process A. Both the call and the reply messages are routed through the bus daemon. The caller includes a different serial number in each call message, and the reply message includes this number to allow the caller to match replies to calls. The call message will contain any arguments to the method. The reply message may indicate an error, or may contain data returned by the method. A method invocation in DBus happens as follows: The language binding may provide a proxy, such that invoking a method on an in-process object invokes a method on a remote object in another process. If so, the application calls a method on the proxy, and the proxy constructs a method call message to send to the remote process. For more low-level APIs, the application may construct a method call message itself, without using a proxy. In either case, the method call message contains: a bus name belonging to the remote process; the name of the method; the arguments to the method; an object path inside the remote process; and optionally the name of the interface that specifies the method. The method call message is sent to the bus daemon. The bus daemon looks at the destination bus name. If a process owns that name, the bus daemon forwards the method call to that process. Otherwise, the bus daemon creates an error message and sends it back as the reply to the method call message. The receiving process unpacks the method call message. In a simple low-level API situation, it may immediately run the method and send a method reply message to the bus daemon. When using a high-level binding API, the binding might examine the object path, interface, and method name, and convert the method call message into an invocation of a method on a native object (GObject, java.lang.Object, QObject, etc.), then convert the return value from the native method into a method reply message. The bus daemon receives the method reply message and sends it to the process that made the method call. The process that made the method call looks at the method reply and makes use of any return values included in the reply. The reply may also indicate that an error occurred. When using a binding, the method reply message may be converted into the return value of of a proxy method, or into an exception. The bus daemon never reorders messages. That is, if you send two method call messages to the same recipient, they will be received in the order they were sent. The recipient is not required to reply to the calls in order, however; for example, it may process each method call in a separate thread, and return reply messages in an undefined order depending on when the threads complete. Method calls have a unique serial number used by the method caller to match reply messages to call messages. Emitting a Signal - Behind the Scenes A signal in DBus consists of a single message, sent by one process to any number of other processes. That is, a signal is a unidirectional broadcast. The signal may contain arguments (a data payload), but because it is a broadcast, it never has a "return value." Contrast this with a method call (see ) where the method call message has a matching method reply message. The emitter (aka sender) of a signal has no knowledge of the signal recipients. Recipients register with the bus daemon to receive signals based on "match rules" - these rules would typically include the sender and the signal name. The bus daemon sends each signal only to recipients who have expressed interest in that signal. A signal in DBus happens as follows: A signal message is created and sent to the bus daemon. When using the low-level API this may be done manually, with certain bindings it may be done for you by the binding when a native object emits a native signal or event. The signal message contains the name of the interface that specifies the signal; the name of the signal; the bus name of the process sending the signal; and any arguments Any process on the message bus can register "match rules" indicating which signals it is interested in. The bus has a list of registered match rules. The bus daemon examines the signal and determines which processes are interested in it. It sends the signal message to these processes. Each process receiving the signal decides what to do with it; if using a binding, the binding may choose to emit a native signal on a proxy object. If using the low-level API, the process may just look at the signal sender and name and decide what to do based on that. Introspection D-Bus objects may support the interface org.freedesktop.DBus.Introspectable. This interface has one method Introspect which takes no arguments and returns an XML string. The XML string describes the interfaces, methods, and signals of the object. See the D-Bus specification for more details on this introspection format. GLib APIs The recommended GLib API for D-Bus is GDBus, which has been distributed with GLib since version 2.26. It is not documented here. See the GLib documentation for details of how to use GDBus. An older API, dbus-glib, also exists. It is deprecated and should not be used in new code. Whenever possible, porting existing code from dbus-glib to GDBus is also recommended. Python API The Python API, dbus-python, is now documented separately in the dbus-python tutorial (also available in doc/tutorial.txt, and doc/tutorial.html if built with python-docutils, in the dbus-python source distribution). Qt API The Qt binding for libdbus, QtDBus, has been distributed with Qt since version 4.2. It is not documented here. See the Qt documentation for details of how to use QtDBus.
    dbus-1.10.6/doc/dbus-test-plan.xml0000644000175000017500000002127612602773110016676 0ustar00smcvsmcv00000000000000
    D-Bus Test Plan 14 February 2003 Anders Carlsson CodeFactory AB
    andersca@codefactory.se
    Introduction This document tries to explain the details of the test plan for D-Bus The importance of testing As with any big library or program, testing is important. It can help find bugs and regressions and make the code better overall. D-Bus is a large and complex piece of software (about 25,000 lines of code for the client library, and 2,500 lines of code for the bus daemon) and it's therefore important to try to make sure that all parts of the software is functioning correctly. D-Bus can be built with support for testing by passing --enable-tests. to the configure script. It is recommended that production systems build without testing since that reduces the D-Bus client library size. Testing the D-Bus client library The tests for the client library consist of the test-dbus program which is a unit test for all aspects of the client library. Whenever a bug in the client library is found and fixed, a test is added to make sure that the bug won't occur again. Data Structures The D-Bus client library consists of some data structures that are used internally; a linked list class, a hashtable class and a string class. All aspects of those are tested by test-dbus. Message loader The message loader is the part of D-Bus that takes messages in raw character form and parses them, turning them into DBusMessages. This is one of the parts of D-Bus that must be absolutely bug-free and robust. The message loader should be able to handle invalid and incomplete messages without crashing. Not doing so is a serious issue and can easily result in D-Bus being exploitable to DoS attacks. To solve these problems, there is a testing feature called the Message Builder. The message builder can take a serialized message in string-form and convert it into a raw character string which can then be loaded by the message loader.
    Example of a message in string form # Standard org.freedesktop.DBus.Hello message VALID_HEADER FIELD_NAME name TYPE STRING STRING 'org.freedesktop.DBus.Hello' FIELD_NAME srvc TYPE STRING STRING 'org.freedesktop.DBus' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body
    The file format of messages in string form is documented in the D-Bus Reference Manual. The message test part of test-dbus is using the message builder to build different kinds of messages, both valid, invalid, and invalid ones, to make sure that the loader won't crash or leak memory of any of those, and that the loader knows if a message is valid or not. There is also a test program called break-loader that loads a message in string-form into raw character form using the message builder. It then randomly changes the message, it can for example replace single bytes of data or modify the length of the message. This is to simulate network errors. The break-loader program saves all the messages leading to errors so it can easily be run for a long period of time.
    Authentication For testing authentication, there is a testing feature that can read authentication sequences from a file and play them back to a dummy server and client to make sure that authentication is working according to the specification.
    Example of an authentication script ## this tests a successful auth of type EXTERNAL SERVER SEND 'AUTH EXTERNAL USERNAME_HEX' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN' EXPECT_STATE AUTHENTICATED
    Testing the D-Bus bus daemon Since the D-Bus bus daemon is using the D-Bus client library it will benefit from all tests done on the client library, but there is still the issue of testing client-server communication. This is more complicated since it it may require another process running. The debug transport In D-Bus, a transport is a class that handles sending and receiving raw data over a certain medium. The transport that is used most in D-Bus is the UNIX transport with sends and recevies data over a UNIX socket. A transport that tunnels data through X11 client messages is also under development. The D-Bus debug transport is a specialized transport that works in-process. This means that a client and server that exists in the same process can talk to eachother without using a socket. The test-bus program The test-bus program is a program that is used to test various parts of the D-Bus bus daemon; robustness and that it conforms to the specifications. The test program has the necessary code from the bus daemon linked in, and it uses the debug transport for communication. This means that the bus daemon code can be tested without the real bus actually running, which makes testing easier. The test-bus program should test all major features of the bus, such as service registration, notification when things occurs and message matching. Other tests Out-Of-Memory robustness Since D-Bus should be able to be used in embedded devices, and also as a system service, it should be able to cope with low-memory situations without exiting or crashing. In practice, this means that both the client and server code must be able to handle dbus_malloc returning NULL. To test this, two environment variables exist. DBUS_MALLOC_FAIL_NTH will make every nth call to dbus_malloc return NULL, and DBUS_MALLOC_FAIL_GREATER_THAN will make any dbus_malloc call with a request for more than the specified number of bytes fail. Memory leaks and code robustness Naturally there are some things that tests can't be written for, for example things like memory leaks and out-of-bounds memory reading or writing. Luckily there exists good tools for catching such errors. One free good tool is Valgrind, which runs the program in a virtual CPU which makes catching errors easy. All test programs can be run under Valgrind,
    dbus-1.10.6/doc/dbus-specification.xml0000644000175000017500000103176712624705346017630 0ustar00smcvsmcv00000000000000
    D-Bus Specification Version 0.26 2015-02-19 Havoc Pennington Red Hat, Inc.
    hp@pobox.com
    Anders Carlsson CodeFactory AB
    andersca@codefactory.se
    Alexander Larsson Red Hat, Inc.
    alexl@redhat.com
    Sven Herzberg Imendio AB
    sven@imendio.com
    Simon McVittie Collabora Ltd.
    simon.mcvittie@collabora.co.uk
    David Zeuthen
    zeuthen@gmail.com
    0.26 2015-02-19 smcv, rh GetConnectionCredentials can return LinuxSecurityLabel or WindowsSID; add privileged BecomeMonitor method 0.25 2014-11-10 smcv, lennart ALLOW_INTERACTIVE_AUTHORIZATION flag, EmitsChangedSignal=const 0.24 2014-10-01 SMcV non-method-calls never expect a reply even without NO_REPLY_EXPECTED; document how to quote match rules 0.23 2014-01-06 SMcV, CY method call messages with no INTERFACE may be considered an error; document tcp:bind=... and nonce-tcp:bind=...; define listenable and connectable addresses 0.22 2013-10-09 add GetConnectionCredentials, document GetAtdAuditSessionData, document GetConnectionSELinuxSecurityContext, document and correct .service file syntax and naming 0.21 2013-04-25 smcv allow Unicode noncharacters in UTF-8 (Unicode Corrigendum #9) 0.20 22 February 2013 smcv, walters reorganise for clarity, remove false claims about basic types, mention /o/fd/DBus 0.19 20 February 2012 smcv/lp formally define unique connection names and well-known bus names; document best practices for interface, bus, member and error names, and object paths; document the search path for session and system services on Unix; document the systemd transport 0.18 29 July 2011 smcv define eavesdropping, unicast, broadcast; add eavesdrop match keyword; promote type system to a top-level section 0.17 1 June 2011 smcv/davidz define ObjectManager; reserve extra pseudo-type-codes used by GVariant 0.16 11 April 2011 add path_namespace, arg0namespace; argNpath matches object paths 0.15 3 November 2010 0.14 12 May 2010 0.13 23 Dezember 2009 0.12 7 November, 2006 0.11 6 February 2005 0.10 28 January 2005 0.9 7 Januar 2005 0.8 06 September 2003 First released document.
    Introduction D-Bus is a system for low-overhead, easy to use interprocess communication (IPC). In more detail: D-Bus is low-overhead because it uses a binary protocol, and does not have to convert to and from a text format such as XML. Because D-Bus is intended for potentially high-resolution same-machine IPC, not primarily for Internet IPC, this is an interesting optimization. D-Bus is also designed to avoid round trips and allow asynchronous operation, much like the X protocol. D-Bus is easy to use because it works in terms of messages rather than byte streams, and automatically handles a lot of the hard IPC issues. Also, the D-Bus library is designed to be wrapped in a way that lets developers use their framework's existing object/type system, rather than learning a new one specifically for IPC. The base D-Bus protocol is a one-to-one (peer-to-peer or client-server) protocol, specified in . That is, it is a system for one application to talk to a single other application. However, the primary intended application of the protocol is the D-Bus message bus, specified in . The message bus is a special application that accepts connections from multiple other applications, and forwards messages among them. Uses of D-Bus include notification of system changes (notification of when a camera is plugged in to a computer, or a new version of some software has been installed), or desktop interoperability, for example a file monitoring service or a configuration service. D-Bus is designed for two specific use cases: A "system bus" for notifications from the system to user sessions, and to allow the system to request input from user sessions. A "session bus" used to implement desktop environments such as GNOME and KDE. D-Bus is not intended to be a generic IPC system for any possible application, and intentionally omits many features found in other IPC systems for this reason. At the same time, the bus daemons offer a number of features not found in other IPC systems, such as single-owner "bus names" (similar to X selections), on-demand startup of services, and security policies. In many ways, these features are the primary motivation for developing D-Bus; other systems would have sufficed if IPC were the only goal. D-Bus may turn out to be useful in unanticipated applications, but future versions of this spec and the reference implementation probably will not incorporate features that interfere with the core use cases. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. However, the document could use a serious audit to be sure it makes sense to do so. Also, they are not capitalized. Protocol and Specification Stability The D-Bus protocol is frozen (only compatible extensions are allowed) as of November 8, 2006. However, this specification could still use a fair bit of work to make interoperable reimplementation possible without reference to the D-Bus reference implementation. Thus, this specification is not marked 1.0. To mark it 1.0, we'd like to see someone invest significant effort in clarifying the specification language, and growing the specification to cover more aspects of the reference implementation's behavior. Until this work is complete, any attempt to reimplement D-Bus will probably require looking at the reference implementation and/or asking questions on the D-Bus mailing list about intended behavior. Questions on the list are very welcome. Nonetheless, this document should be a useful starting point and is to our knowledge accurate, though incomplete. Type System D-Bus has a type system, in which values of various types can be serialized into a sequence of bytes referred to as the wire format in a standard way. Converting a value from some other representation into the wire format is called marshaling and converting it back from the wire format is unmarshaling. The D-Bus protocol does not include type tags in the marshaled data; a block of marshaled values must have a known type signature. The type signature is made up of zero or more single complete types, each made up of one or more type codes. A type code is an ASCII character representing the type of a value. Because ASCII characters are used, the type signature will always form a valid ASCII string. A simple string compare determines whether two type signatures are equivalent. A single complete type is a sequence of type codes that fully describes one type: either a basic type, or a single fully-described container type. A single complete type is a basic type code, a variant type code, an array with its element type, or a struct with its fields (all of which are defined below). So the following signatures are not single complete types: "aa" "(ii" "ii)" And the following signatures contain multiple complete types: "ii" "aiai" "(ii)(ii)" Note however that a single complete type may contain multiple other single complete types, by containing a struct or dict entry. Basic types The simplest type codes are the basic types, which are the types whose structure is entirely defined by their 1-character type code. Basic types consist of fixed types and string-like types. The fixed types are basic types whose values have a fixed length, namely BYTE, BOOLEAN, DOUBLE, UNIX_FD, and signed or unsigned integers of length 16, 32 or 64 bits. As a simple example, the type code for 32-bit integer (INT32) is the ASCII character 'i'. So the signature for a block of values containing a single INT32 would be: "i" A block of values containing two INT32 would have this signature: "ii" The characteristics of the fixed types are listed in this table. Conventional name ASCII type-code Encoding BYTE y (121) Unsigned 8-bit integer BOOLEAN b (98) Boolean value: 0 is false, 1 is true, any other value allowed by the marshalling format is invalid INT16 n (110) Signed (two's complement) 16-bit integer UINT16 q (113) Unsigned 16-bit integer INT32 i (105) Signed (two's complement) 32-bit integer UINT32 u (117) Unsigned 32-bit integer INT64 x (120) Signed (two's complement) 64-bit integer (mnemonic: x and t are the first characters in "sixty" not already used for something more common) UINT64 t (116) Unsigned 64-bit integer DOUBLE d (100) IEEE 754 double-precision floating point UNIX_FD h (104) Unsigned 32-bit integer representing an index into an out-of-band array of file descriptors, transferred via some platform-specific mechanism (mnemonic: h for handle) The string-like types are basic types with a variable length. The value of any string-like type is conceptually 0 or more Unicode codepoints encoded in UTF-8, none of which may be U+0000. The UTF-8 text must be validated strictly: in particular, it must not contain overlong sequences or codepoints above U+10FFFF. Since D-Bus Specification version 0.21, in accordance with Unicode Corrigendum #9, the "noncharacters" U+FDD0..U+FDEF, U+nFFFE and U+nFFFF are allowed in UTF-8 strings (but note that older versions of D-Bus rejected these noncharacters). The marshalling formats for the string-like types all end with a single zero (NUL) byte, but that byte is not considered to be part of the text. The characteristics of the string-like types are listed in this table. Conventional name ASCII type-code Validity constraints STRING s (115) No extra constraints OBJECT_PATH o (111) Must be a syntactically valid object path SIGNATURE g (103) Zero or more single complete types Valid Object Paths An object path is a name used to refer to an object instance. Conceptually, each participant in a D-Bus message exchange may have any number of object instances (think of C++ or Java objects) and each such instance will have a path. Like a filesystem, the object instances in an application form a hierarchical tree. Object paths are often namespaced by starting with a reversed domain name and containing an interface version number, in the same way as interface names and well-known bus names. This makes it possible to implement more than one service, or more than one version of a service, in the same process, even if the services share a connection but cannot otherwise co-operate (for instance, if they are implemented by different plugins). For instance, if the owner of example.com is developing a D-Bus API for a music player, they might use the hierarchy of object paths that start with /com/example/MusicPlayer1 for its objects. The following rules define a valid object path. Implementations must not send or accept messages with invalid object paths. The path may be of any length. The path must begin with an ASCII '/' (integer 47) character, and must consist of elements separated by slash characters. Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" No element may be the empty string. Multiple '/' characters cannot occur in sequence. A trailing '/' character is not allowed unless the path is the root path (a single '/' character). Valid Signatures An implementation must not send or accept invalid signatures. Valid signatures will conform to the following rules: The signature is a list of single complete types. Arrays must have element types, and structs must have both open and close parentheses. Only type codes, open and close parentheses, and open and close curly brackets are allowed in the signature. The STRUCT type code is not allowed in signatures, because parentheses are used instead. Similarly, the DICT_ENTRY type code is not allowed in signatures, because curly brackets are used instead. The maximum depth of container type nesting is 32 array type codes and 32 open parentheses. This implies that the maximum total depth of recursion is 64, for an "array of array of array of ... struct of struct of struct of ..." where there are 32 array and 32 struct. The maximum length of a signature is 255. When signatures appear in messages, the marshalling format guarantees that they will be followed by a nul byte (which can be interpreted as either C-style string termination or the INVALID type-code), but this is not conceptually part of the signature. Container types In addition to basic types, there are four container types: STRUCT, ARRAY, VARIANT, and DICT_ENTRY. STRUCT has a type code, ASCII character 'r', but this type code does not appear in signatures. Instead, ASCII characters '(' and ')' are used to mark the beginning and end of the struct. So for example, a struct containing two integers would have this signature: "(ii)" Structs can be nested, so for example a struct containing an integer and another struct: "(i(ii))" The value block storing that struct would contain three integers; the type signature allows you to distinguish "(i(ii))" from "((ii)i)" or "(iii)" or "iii". The STRUCT type code 'r' is not currently used in the D-Bus protocol, but is useful in code that implements the protocol. This type code is specified to allow such code to interoperate in non-protocol contexts. Empty structures are not allowed; there must be at least one type code between the parentheses. ARRAY has ASCII character 'a' as type code. The array type code must be followed by a single complete type. The single complete type following the array is the type of each array element. So the simple example is: "ai" which is an array of 32-bit integers. But an array can be of any type, such as this array-of-struct-with-two-int32-fields: "a(ii)" Or this array of array of integer: "aai" VARIANT has ASCII character 'v' as its type code. A marshaled value of type VARIANT will have the signature of a single complete type as part of the value. This signature will be followed by a marshaled value of that type. Unlike a message signature, the variant signature can contain only a single complete type. So "i", "ai" or "(ii)" is OK, but "ii" is not. Use of variants may not cause a total message depth to be larger than 64, including other container types such as structures. A DICT_ENTRY works exactly like a struct, but rather than parentheses it uses curly braces, and it has more restrictions. The restrictions are: it occurs only as an array element type; it has exactly two single complete types inside the curly braces; the first single complete type (the "key") must be a basic type rather than a container type. Implementations must not accept dict entries outside of arrays, must not accept dict entries with zero, one, or more than two fields, and must not accept dict entries with non-basic-typed keys. A dict entry is always a key-value pair. The first field in the DICT_ENTRY is always the key. A message is considered corrupt if the same key occurs twice in the same array of DICT_ENTRY. However, for performance reasons implementations are not required to reject dicts with duplicate keys. In most languages, an array of dict entry would be represented as a map, hash table, or dict object. Summary of types The following table summarizes the D-Bus types. Category Conventional Name Code Description reserved INVALID 0 (ASCII NUL) Not a valid type code, used to terminate signatures fixed, basic BYTE 121 (ASCII 'y') 8-bit unsigned integer fixed, basic BOOLEAN 98 (ASCII 'b') Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid. fixed, basic INT16 110 (ASCII 'n') 16-bit signed integer fixed, basic UINT16 113 (ASCII 'q') 16-bit unsigned integer fixed, basic INT32 105 (ASCII 'i') 32-bit signed integer fixed, basic UINT32 117 (ASCII 'u') 32-bit unsigned integer fixed, basic INT64 120 (ASCII 'x') 64-bit signed integer fixed, basic UINT64 116 (ASCII 't') 64-bit unsigned integer fixed, basic DOUBLE 100 (ASCII 'd') IEEE 754 double string-like, basic STRING 115 (ASCII 's') UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes. string-like, basic OBJECT_PATH 111 (ASCII 'o') Name of an object instance string-like, basic SIGNATURE 103 (ASCII 'g') A type signature container ARRAY 97 (ASCII 'a') Array container STRUCT 114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')') Struct; type code 114 'r' is reserved for use in bindings and implementations to represent the general concept of a struct, and must not appear in signatures used on D-Bus. container VARIANT 118 (ASCII 'v') Variant type (the type of the value is part of the value itself) container DICT_ENTRY 101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') Entry in a dict or map (array of key-value pairs). Type code 101 'e' is reserved for use in bindings and implementations to represent the general concept of a dict or dict-entry, and must not appear in signatures used on D-Bus. fixed, basic UNIX_FD 104 (ASCII 'h') Unix file descriptor reserved (reserved) 109 (ASCII 'm') Reserved for a 'maybe' type compatible with the one in GVariant, and must not appear in signatures used on D-Bus until specified here reserved (reserved) 42 (ASCII '*') Reserved for use in bindings/implementations to represent any single complete type, and must not appear in signatures used on D-Bus. reserved (reserved) 63 (ASCII '?') Reserved for use in bindings/implementations to represent any basic type, and must not appear in signatures used on D-Bus. reserved (reserved) 64 (ASCII '@'), 38 (ASCII '&'), 94 (ASCII '^') Reserved for internal use by bindings/implementations, and must not appear in signatures used on D-Bus. GVariant uses these type-codes to encode calling conventions. Marshaling (Wire Format) D-Bus defines a marshalling format for its type system, which is used in D-Bus messages. This is not the only possible marshalling format for the type system: for instance, GVariant (part of GLib) re-uses the D-Bus type system but implements an alternative marshalling format. Byte order and alignment Given a type signature, a block of bytes can be converted into typed values. This section describes the format of the block of bytes. Byte order and alignment issues are handled uniformly for all D-Bus types. A block of bytes has an associated byte order. The byte order has to be discovered in some way; for D-Bus messages, the byte order is part of the message header as described in . For now, assume that the byte order is known to be either little endian or big endian. Each value in a block of bytes is aligned "naturally," for example 4-byte values are aligned to a 4-byte boundary, and 8-byte values to an 8-byte boundary. To properly align a value, alignment padding may be necessary. The alignment padding must always be the minimum required padding to properly align the following value; and it must always be made up of nul bytes. The alignment padding must not be left uninitialized (it can't contain garbage), and more padding than required must not be used. As an exception to natural alignment, STRUCT and DICT_ENTRY values are always aligned to an 8-byte boundary, regardless of the alignments of their contents. Marshalling basic types To marshal and unmarshal fixed types, you simply read one value from the data block corresponding to each type code in the signature. All signed integer values are encoded in two's complement, DOUBLE values are IEEE 754 double-precision floating-point, and BOOLEAN values are encoded in 32 bits (of which only the least significant bit is used). The string-like types are all marshalled as a fixed-length unsigned integer n giving the length of the variable part, followed by n nonzero bytes of UTF-8 text, followed by a single zero (nul) byte which is not considered to be part of the text. The alignment of the string-like type is the same as the alignment of n. For the STRING and OBJECT_PATH types, n is encoded in 4 bytes, leading to 4-byte alignment. For the SIGNATURE type, n is encoded as a single byte. As a result, alignment padding is never required before a SIGNATURE. Marshalling containers Arrays are marshalled as a UINT32 n giving the length of the array data in bytes, followed by alignment padding to the alignment boundary of the array element type, followed by the n bytes of the array elements marshalled in sequence. n does not include the padding after the length, or any padding after the last element. For instance, if the current position in the message is a multiple of 8 bytes and the byte-order is big-endian, an array containing only the 64-bit integer 5 would be marshalled as: 00 00 00 08 8 bytes of data 00 00 00 00 padding to 8-byte boundary 00 00 00 00 00 00 00 05 first element = 5 Arrays have a maximum length defined to be 2 to the 26th power or 67108864 (64 MiB). Implementations must not send or accept arrays exceeding this length. Structs and dict entries are marshalled in the same way as their contents, but their alignment is always to an 8-byte boundary, even if their contents would normally be less strictly aligned. Variants are marshalled as the SIGNATURE of the contents (which must be a single complete type), followed by a marshalled value with the type given by that signature. The variant has the same 1-byte alignment as the signature, which means that alignment padding before a variant is never needed. Use of variants may not cause a total message depth to be larger than 64, including other container types such as structures. Summary of D-Bus marshalling Given all this, the types are marshaled on the wire as follows: Conventional Name Encoding Alignment INVALID Not applicable; cannot be marshaled. N/A BYTE A single 8-bit byte. 1 BOOLEAN As for UINT32, but only 0 and 1 are valid values. 4 INT16 16-bit signed integer in the message's byte order. 2 UINT16 16-bit unsigned integer in the message's byte order. 2 INT32 32-bit signed integer in the message's byte order. 4 UINT32 32-bit unsigned integer in the message's byte order. 4 INT64 64-bit signed integer in the message's byte order. 8 UINT64 64-bit unsigned integer in the message's byte order. 8 DOUBLE 64-bit IEEE 754 double in the message's byte order. 8 STRING A UINT32 indicating the string's length in bytes excluding its terminating nul, followed by non-nul string data of the given length, followed by a terminating nul byte. 4 (for the length) OBJECT_PATH Exactly the same as STRING except the content must be a valid object path (see above). 4 (for the length) SIGNATURE The same as STRING except the length is a single byte (thus signatures have a maximum length of 255) and the content must be a valid signature (see above). 1 ARRAY A UINT32 giving the length of the array data in bytes, followed by alignment padding to the alignment boundary of the array element type, followed by each array element. 4 (for the length) STRUCT A struct must start on an 8-byte boundary regardless of the type of the struct fields. The struct value consists of each field marshaled in sequence starting from that 8-byte alignment boundary. 8 VARIANT The marshaled SIGNATURE of a single complete type, followed by a marshaled value with the type given in the signature. 1 (alignment of the signature) DICT_ENTRY Identical to STRUCT. 8 UNIX_FD 32-bit unsigned integer in the message's byte order. The actual file descriptors need to be transferred out-of-band via some platform specific mechanism. On the wire, values of this type store the index to the file descriptor in the array of file descriptors that accompany the message. 4 Message Protocol A message consists of a header and a body. If you think of a message as a package, the header is the address, and the body contains the package contents. The message delivery system uses the header information to figure out where to send the message and how to interpret it; the recipient interprets the body of the message. The body of the message is made up of zero or more arguments, which are typed values, such as an integer or a byte array. Both header and body use the D-Bus type system and format for serializing data. Message Format A message consists of a header and a body. The header is a block of values with a fixed signature and meaning. The body is a separate block of values, with a signature specified in the header. The length of the header must be a multiple of 8, allowing the body to begin on an 8-byte boundary when storing the entire message in a single buffer. If the header does not naturally end on an 8-byte boundary up to 7 bytes of nul-initialized alignment padding must be added. The message body need not end on an 8-byte boundary. The maximum length of a message, including header, header alignment padding, and body is 2 to the 27th power or 134217728 (128 MiB). Implementations must not send or accept messages exceeding this size. The signature of the header is: "yyyyuua(yv)" Written out more readably, this is: BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT) These values have the following meanings: Value Description 1st BYTE Endianness flag; ASCII 'l' for little-endian or ASCII 'B' for big-endian. Both header and body are in this endianness. 2nd BYTE Message type. Unknown types must be ignored. Currently-defined types are described below. 3rd BYTE Bitwise OR of flags. Unknown flags must be ignored. Currently-defined flags are described below. 4th BYTE Major protocol version of the sending application. If the major protocol version of the receiving application does not match, the applications will not be able to communicate and the D-Bus connection must be disconnected. The major protocol version for this version of the specification is 1. 1st UINT32 Length in bytes of the message body, starting from the end of the header. The header ends after its alignment padding to an 8-boundary. 2nd UINT32 The serial of this message, used as a cookie by the sender to identify the reply corresponding to this request. This must not be zero. ARRAY of STRUCT of (BYTE,VARIANT) An array of zero or more header fields where the byte is the field code, and the variant is the field value. The message type determines which fields are required. Message types that can appear in the second byte of the header are: Conventional name Decimal value Description INVALID 0 This is an invalid type. METHOD_CALL 1 Method call. This message type may prompt a reply. METHOD_RETURN 2 Method reply with returned data. ERROR 3 Error reply. If the first argument exists and is a string, it is an error message. SIGNAL 4 Signal emission. Flags that can appear in the third byte of the header: Conventional name Hex value Description NO_REPLY_EXPECTED 0x1 This message does not expect method return replies or error replies, even if it is of a type that can have a reply; the reply can be omitted as an optimization. It is compliant with this specification to return the reply despite this flag, although doing so on a bus with a non-trivial security policy (such as the well-known system bus) may result in access denial messages being logged for the reply. Note that METHOD_CALL is the only message type currently defined in this specification that can expect a reply, so the presence or absence of this flag in the other three message types that are currently documented is meaningless: replies to those message types should not be sent, whether this flag is present or not. NO_AUTO_START 0x2 The bus must not launch an owner for the destination name in response to this message. ALLOW_INTERACTIVE_AUTHORIZATION 0x4 This flag may be set on a method call message to inform the receiving side that the caller is prepared to wait for interactive authorization, which might take a considerable time to complete. For instance, if this flag is set, it would be appropriate to query the user for passwords or confirmation via Polkit or a similar framework. This flag is only useful when unprivileged code calls a more privileged method call, and an authorization framework is deployed that allows possibly interactive authorization. If no such framework is deployed it has no effect. This flag should not be set by default by client implementations. If it is set, the caller should also set a suitably long timeout on the method call to make sure the user interaction may complete. This flag is only valid for method call messages, and shall be ignored otherwise. Interaction that takes place as a part of the effect of the method being called is outside the scope of this flag, even if it could also be characterized as authentication or authorization. For instance, in a method call that directs a network management service to attempt to connect to a virtual private network, this flag should control how the network management service makes the decision "is this user allowed to change system network configuration?", but it should not affect how or whether the network management service interacts with the user to obtain the credentials that are required for access to the VPN. If a this flag is not set on a method call, and a service determines that the requested operation is not allowed without interactive authorization, but could be allowed after successful interactive authorization, it may return the org.freedesktop.DBus.Error.InteractiveAuthorizationRequired error. The absence of this flag does not guarantee that interactive authorization will not be applied, since existing services that pre-date this flag might already use interactive authorization. However, existing D-Bus APIs that will use interactive authorization should document that the call may take longer than usual, and new D-Bus APIs should avoid interactive authorization in the absence of this flag. Header Fields The array at the end of the header contains header fields, where each field is a 1-byte field code followed by a field value. A header must contain the required header fields for its message type, and zero or more of any optional header fields. Future versions of this protocol specification may add new fields. Implementations must ignore fields they do not understand. Implementations must not invent their own header fields; only changes to this specification may introduce new header fields. Again, if an implementation sees a header field code that it does not expect, it must ignore that field, as it will be part of a new (but compatible) version of this specification. This also applies to known header fields appearing in unexpected messages, for example: if a signal has a reply serial it must be ignored even though it has no meaning as of this version of the spec. However, implementations must not send or accept known header fields with the wrong type stored in the field value. So for example a message with an INTERFACE field of type UINT32 would be considered corrupt. Here are the currently-defined header fields: Conventional Name Decimal Code Type Required In Description INVALID 0 N/A not allowed Not a valid field name (error if it appears in a message) PATH 1 OBJECT_PATH METHOD_CALL, SIGNAL The object to send a call to, or the object a signal is emitted from. The special path /org/freedesktop/DBus/Local is reserved; implementations should not send messages with this path, and the reference implementation of the bus daemon will disconnect any application that attempts to do so. INTERFACE 2 STRING SIGNAL The interface to invoke a method call on, or that a signal is emitted from. Optional for method calls, required for signals. The special interface org.freedesktop.DBus.Local is reserved; implementations should not send messages with this interface, and the reference implementation of the bus daemon will disconnect any application that attempts to do so. MEMBER 3 STRING METHOD_CALL, SIGNAL The member, either the method name or signal name. ERROR_NAME 4 STRING ERROR The name of the error that occurred, for errors REPLY_SERIAL 5 UINT32 ERROR, METHOD_RETURN The serial number of the message this message is a reply to. (The serial number is the second UINT32 in the header.) DESTINATION 6 STRING optional The name of the connection this message is intended for. Only used in combination with the message bus, see . SENDER 7 STRING optional Unique name of the sending connection. The message bus fills in this field so it is reliable; the field is only meaningful in combination with the message bus. SIGNATURE 8 SIGNATURE optional The signature of the message body. If omitted, it is assumed to be the empty signature "" (i.e. the body must be 0-length). UNIX_FDS 9 UINT32 optional The number of Unix file descriptors that accompany the message. If omitted, it is assumed that no Unix file descriptors accompany the message. The actual file descriptors need to be transferred via platform specific mechanism out-of-band. They must be sent at the same time as part of the message itself. They may not be sent before the first byte of the message itself is transferred or after the last byte of the message itself. Valid Names The various names in D-Bus messages have some restrictions. There is a maximum name length of 255 which applies to bus names, interfaces, and members. Interface names Interfaces have names with type STRING, meaning that they must be valid UTF-8. However, there are also some additional restrictions that apply to interface names specifically: Interface names are composed of 1 or more elements separated by a period ('.') character. All elements must contain at least one character. Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" and must not begin with a digit. Interface names must contain at least one '.' (period) character (and thus at least two elements). Interface names must not begin with a '.' (period) character. Interface names must not exceed the maximum name length. Interface names should start with the reversed DNS domain name of the author of the interface (in lower-case), like interface names in Java. It is conventional for the rest of the interface name to consist of words run together, with initial capital letters on all words ("CamelCase"). Several levels of hierarchy can be used. It is also a good idea to include the major version of the interface in the name, and increment it if incompatible changes are made; this way, a single object can implement several versions of an interface in parallel, if necessary. For instance, if the owner of example.com is developing a D-Bus API for a music player, they might define interfaces called com.example.MusicPlayer1, com.example.MusicPlayer1.Track and com.example.MusicPlayer1.Seekable. D-Bus does not distinguish between the concepts that would be called classes and interfaces in Java: either can be identified on D-Bus by an interface name. Bus names Connections have one or more bus names associated with them. A connection has exactly one bus name that is a unique connection name. The unique connection name remains with the connection for its entire lifetime. A bus name is of type STRING, meaning that it must be valid UTF-8. However, there are also some additional restrictions that apply to bus names specifically: Bus names that start with a colon (':') character are unique connection names. Other bus names are called well-known bus names. Bus names are composed of 1 or more elements separated by a period ('.') character. All elements must contain at least one character. Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-". Only elements that are part of a unique connection name may begin with a digit, elements in other bus names must not begin with a digit. Bus names must contain at least one '.' (period) character (and thus at least two elements). Bus names must not begin with a '.' (period) character. Bus names must not exceed the maximum name length. Note that the hyphen ('-') character is allowed in bus names but not in interface names. Like interface names, well-known bus names should start with the reversed DNS domain name of the author of the interface (in lower-case), and it is conventional for the rest of the well-known bus name to consist of words run together, with initial capital letters. As with interface names, including a version number in well-known bus names is a good idea; it's possible to have the well-known bus name for more than one version simultaneously if backwards compatibility is required. If a well-known bus name implies the presence of a "main" interface, that "main" interface is often given the same name as the well-known bus name, and situated at the corresponding object path. For instance, if the owner of example.com is developing a D-Bus API for a music player, they might define that any application that takes the well-known name com.example.MusicPlayer1 should have an object at the object path /com/example/MusicPlayer1 which implements the interface com.example.MusicPlayer1. Member names Member (i.e. method or signal) names: Must only contain the ASCII characters "[A-Z][a-z][0-9]_" and may not begin with a digit. Must not contain the '.' (period) character. Must not exceed the maximum name length. Must be at least 1 byte in length. It is conventional for member names on D-Bus to consist of capitalized words with no punctuation ("camel-case"). Method names should usually be verbs, such as GetItems, and signal names should usually be a description of an event, such as ItemsChanged. Error names Error names have the same restrictions as interface names. Error names have the same naming conventions as interface names, and often contain .Error.; for instance, the owner of example.com might define the errors com.example.MusicPlayer.Error.FileNotFound and com.example.MusicPlayer.Error.OutOfMemory. The errors defined by D-Bus itself, such as org.freedesktop.DBus.Error.Failed, follow a similar pattern. Message Types Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and SIGNAL) has its own expected usage conventions and header fields. This section describes these conventions. Method Calls Some messages invoke an operation on a remote object. These are called method call messages and have the type tag METHOD_CALL. Such messages map naturally to methods on objects in a typical program. A method call message is required to have a MEMBER header field indicating the name of the method. Optionally, the message has an INTERFACE field giving the interface the method is a part of. Including the INTERFACE in all method call messages is strongly recommended. In the absence of an INTERFACE field, if two or more interfaces on the same object have a method with the same name, it is undefined which of those methods will be invoked. Implementations may choose to either return an error, or deliver the message as though it had an arbitrary one of those interfaces. In some situations (such as the well-known system bus), messages are filtered through an access-control list external to the remote object implementation. If that filter rejects certain messages by matching their interface, or accepts only messages to specific interfaces, it must also reject messages that have no INTERFACE: otherwise, malicious applications could use this to bypass the filter. Method call messages also include a PATH field indicating the object to invoke the method on. If the call is passing through a message bus, the message will also have a DESTINATION field giving the name of the connection to receive the message. When an application handles a method call message, it is required to return a reply. The reply is identified by a REPLY_SERIAL header field indicating the serial number of the METHOD_CALL being replied to. The reply can have one of two types; either METHOD_RETURN or ERROR. If the reply has type METHOD_RETURN, the arguments to the reply message are the return value(s) or "out parameters" of the method call. If the reply has type ERROR, then an "exception" has been thrown, and the call fails; no return value will be provided. It makes no sense to send multiple replies to the same method call. Even if a method call has no return values, a METHOD_RETURN reply is required, so the caller will know the method was successfully processed. The METHOD_RETURN or ERROR reply message must have the REPLY_SERIAL header field. If a METHOD_CALL message has the flag NO_REPLY_EXPECTED, then as an optimization the application receiving the method call may choose to omit the reply message (regardless of whether the reply would have been METHOD_RETURN or ERROR). However, it is also acceptable to ignore the NO_REPLY_EXPECTED flag and reply anyway. Unless a message has the flag NO_AUTO_START, if the destination name does not exist then a program to own the destination name will be started before the message is delivered. The message will be held until the new program is successfully started or has failed to start; in case of failure, an error will be returned. This flag is only relevant in the context of a message bus, it is ignored during one-to-one communication with no intermediate bus. Mapping method calls to native APIs APIs for D-Bus may map method calls to a method call in a specific programming language, such as C++, or may map a method call written in an IDL to a D-Bus message. In APIs of this nature, arguments to a method are often termed "in" (which implies sent in the METHOD_CALL), or "out" (which implies returned in the METHOD_RETURN). Some APIs such as CORBA also have "inout" arguments, which are both sent and received, i.e. the caller passes in a value which is modified. Mapped to D-Bus, an "inout" argument is equivalent to an "in" argument, followed by an "out" argument. You can't pass things "by reference" over the wire, so "inout" is purely an illusion of the in-process API. Given a method with zero or one return values, followed by zero or more arguments, where each argument may be "in", "out", or "inout", the caller constructs a message by appending each "in" or "inout" argument, in order. "out" arguments are not represented in the caller's message. The recipient constructs a reply by appending first the return value if any, then each "out" or "inout" argument, in order. "in" arguments are not represented in the reply message. Error replies are normally mapped to exceptions in languages that have exceptions. In converting from native APIs to D-Bus, it is perhaps nice to map D-Bus naming conventions ("FooBar") to native conventions such as "fooBar" or "foo_bar" automatically. This is OK as long as you can say that the native API is one that was specifically written for D-Bus. It makes the most sense when writing object implementations that will be exported over the bus. Object proxies used to invoke remote D-Bus objects probably need the ability to call any D-Bus method, and thus a magic name mapping like this could be a problem. This specification doesn't require anything of native API bindings; the preceding is only a suggested convention for consistency among bindings. Signal Emission Unlike method calls, signal emissions have no replies. A signal emission is simply a single message of type SIGNAL. It must have three header fields: PATH giving the object the signal was emitted from, plus INTERFACE and MEMBER giving the fully-qualified name of the signal. The INTERFACE header is required for signals, though it is optional for method calls. Errors Messages of type ERROR are most commonly replies to a METHOD_CALL, but may be returned in reply to any kind of message. The message bus for example will return an ERROR in reply to a signal emission if the bus does not have enough memory to send the signal. An ERROR may have any arguments, but if the first argument is a STRING, it must be an error message. The error message may be logged or shown to the user in some way. Notation in this document This document uses a simple pseudo-IDL to describe particular method calls and signals. Here is an example of a method call: org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags, out UINT32 resultcode) This means INTERFACE = org.freedesktop.DBus, MEMBER = StartServiceByName, METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument is UINT32. Remember that the MEMBER field can't contain any '.' (period) characters so it's known that the last part of the name in the "IDL" is the member name. In C++ that might end up looking like this: unsigned int org::freedesktop::DBus::StartServiceByName (const char *name, unsigned int flags); or equally valid, the return value could be done as an argument: void org::freedesktop::DBus::StartServiceByName (const char *name, unsigned int flags, unsigned int *resultcode); It's really up to the API designer how they want to make this look. You could design an API where the namespace wasn't used in C++, using STL or Qt, using varargs, or whatever you wanted. Signals are written as follows: org.freedesktop.DBus.NameLost (STRING name) Signals don't specify "in" vs. "out" because only a single direction is possible. It isn't especially encouraged to use this lame pseudo-IDL in actual API implementations; you might use the native notation for the language you're using, or you might use COM or CORBA IDL, for example. Invalid Protocol and Spec Extensions For security reasons, the D-Bus protocol should be strictly parsed and validated, with the exception of defined extension points. Any invalid protocol or spec violations should result in immediately dropping the connection without notice to the other end. Exceptions should be carefully considered, e.g. an exception may be warranted for a well-understood idiosyncrasy of a widely-deployed implementation. In cases where the other end of a connection is 100% trusted and known to be friendly, skipping validation for performance reasons could also make sense in certain cases. Generally speaking violations of the "must" requirements in this spec should be considered possible attempts to exploit security, and violations of the "should" suggestions should be considered legitimate (though perhaps they should generate an error in some cases). The following extension points are built in to D-Bus on purpose and must not be treated as invalid protocol. The extension points are intended for use by future versions of this spec, they are not intended for third parties. At the moment, the only way a third party could extend D-Bus without breaking interoperability would be to introduce a way to negotiate new feature support as part of the auth protocol, using EXTENSION_-prefixed commands. There is not yet a standard way to negotiate features. In the authentication protocol (see ) unknown commands result in an ERROR rather than a disconnect. This enables future extensions to the protocol. Commands starting with EXTENSION_ are reserved for third parties. The authentication protocol supports pluggable auth mechanisms. The address format (see ) supports new kinds of transport. Messages with an unknown type (something other than METHOD_CALL, METHOD_RETURN, ERROR, SIGNAL) are ignored. Unknown-type messages must still be well-formed in the same way as the known messages, however. They still have the normal header and body. Header fields with an unknown or unexpected field code must be ignored, though again they must still be well-formed. New standard interfaces (with new methods and signals) can of course be added. Authentication Protocol Before the flow of messages begins, two applications must authenticate. A simple plain-text protocol is used for authentication; this protocol is a SASL profile, and maps fairly directly from the SASL specification. The message encoding is NOT used here, only plain text messages. In examples, "C:" and "S:" indicate lines sent by the client and server respectively. Protocol Overview The protocol is a line-based protocol, where each line ends with \r\n. Each line begins with an all-caps ASCII command name containing only the character range [A-Z_], a space, then any arguments for the command, then the \r\n ending the line. The protocol is case-sensitive. All bytes must be in the ASCII character set. Commands from the client to the server are as follows: AUTH [mechanism] [initial-response] CANCEL BEGIN DATA <data in hex encoding> ERROR [human-readable error explanation] NEGOTIATE_UNIX_FD From server to client are as follows: REJECTED <space-separated list of mechanism names> OK <GUID in hex> DATA <data in hex encoding> ERROR AGREE_UNIX_FD Unofficial extensions to the command set must begin with the letters "EXTENSION_", to avoid conflicts with future official commands. For example, "EXTENSION_COM_MYDOMAIN_DO_STUFF". Special credentials-passing nul byte Immediately after connecting to the server, the client must send a single nul byte. This byte may be accompanied by credentials information on some operating systems that use sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass credentials over UNIX domain sockets. However, the nul byte must be sent even on other kinds of socket, and even on operating systems that do not require a byte to be sent in order to transmit credentials. The text protocol described in this document begins after the single nul byte. If the first byte received from the client is not a nul byte, the server may disconnect that client. A nul byte in any context other than the initial byte is an error; the protocol is ASCII-only. The credentials sent along with the nul byte may be used with the SASL mechanism EXTERNAL. AUTH command If an AUTH command has no arguments, it is a request to list available mechanisms. The server must respond with a REJECTED command listing the mechanisms it understands, or with an error. If an AUTH command specifies a mechanism, and the server supports said mechanism, the server should begin exchanging SASL challenge-response data with the client using DATA commands. If the server does not support the mechanism given in the AUTH command, it must send either a REJECTED command listing the mechanisms it does support, or an error. If the [initial-response] argument is provided, it is intended for use with mechanisms that have no initial challenge (or an empty initial challenge), as if it were the argument to an initial DATA command. If the selected mechanism has an initial challenge and [initial-response] was provided, the server should reject authentication by sending REJECTED. If authentication succeeds after exchanging DATA commands, an OK command must be sent to the client. The first octet received by the server after the \r\n of the BEGIN command from the client must be the first octet of the authenticated/encrypted stream of D-Bus messages. If BEGIN is received by the server, the first octet received by the client after the \r\n of the OK command must be the first octet of the authenticated/encrypted stream of D-Bus messages. CANCEL Command At any time up to sending the BEGIN command, the client may send a CANCEL command. On receiving the CANCEL command, the server must send a REJECTED command and abort the current authentication exchange. DATA Command The DATA command may come from either client or server, and simply contains a hex-encoded block of data to be interpreted according to the SASL mechanism in use. Some SASL mechanisms support sending an "empty string"; FIXME we need some way to do this. BEGIN Command The BEGIN command acknowledges that the client has received an OK command from the server, and that the stream of messages is about to begin. The first octet received by the server after the \r\n of the BEGIN command from the client must be the first octet of the authenticated/encrypted stream of D-Bus messages. REJECTED Command The REJECTED command indicates that the current authentication exchange has failed, and further exchange of DATA is inappropriate. The client would normally try another mechanism, or try providing different responses to challenges. Optionally, the REJECTED command has a space-separated list of available auth mechanisms as arguments. If a server ever provides a list of supported mechanisms, it must provide the same list each time it sends a REJECTED message. Clients are free to ignore all lists received after the first. OK Command The OK command indicates that the client has been authenticated. The client may now proceed with negotiating Unix file descriptor passing. To do that it shall send NEGOTIATE_UNIX_FD to the server. Otherwise, the client must respond to the OK command by sending a BEGIN command, followed by its stream of messages, or by disconnecting. The server must not accept additional commands using this protocol after the BEGIN command has been received. Further communication will be a stream of D-Bus messages (optionally encrypted, as negotiated) rather than this protocol. If a client sends BEGIN the first octet received by the client after the \r\n of the OK command must be the first octet of the authenticated/encrypted stream of D-Bus messages. The OK command has one argument, which is the GUID of the server. See for more on server GUIDs. ERROR Command The ERROR command indicates that either server or client did not know a command, does not accept the given command in the current context, or did not understand the arguments to the command. This allows the protocol to be extended; a client or server can send a command present or permitted only in new protocol versions, and if an ERROR is received instead of an appropriate response, fall back to using some other technique. If an ERROR is sent, the server or client that sent the error must continue as if the command causing the ERROR had never been received. However, the the server or client receiving the error should try something other than whatever caused the error; if only canceling/rejecting the authentication. If the D-Bus protocol changes incompatibly at some future time, applications implementing the new protocol would probably be able to check for support of the new protocol by sending a new command and receiving an ERROR from applications that don't understand it. Thus the ERROR feature of the auth protocol is an escape hatch that lets us negotiate extensions or changes to the D-Bus protocol in the future. NEGOTIATE_UNIX_FD Command The NEGOTIATE_UNIX_FD command indicates that the client supports Unix file descriptor passing. This command may only be sent after the connection is authenticated, i.e. after OK was received by the client. This command may only be sent on transports that support Unix file descriptor passing. On receiving NEGOTIATE_UNIX_FD the server must respond with either AGREE_UNIX_FD or ERROR. It shall respond the former if the transport chosen supports Unix file descriptor passing and the server supports this feature. It shall respond the latter if the transport does not support Unix file descriptor passing, the server does not support this feature, or the server decides not to enable file descriptor passing due to security or other reasons. AGREE_UNIX_FD Command The AGREE_UNIX_FD command indicates that the server supports Unix file descriptor passing. This command may only be sent after the connection is authenticated, and the client sent NEGOTIATE_UNIX_FD to enable Unix file descriptor passing. This command may only be sent on transports that support Unix file descriptor passing. On receiving AGREE_UNIX_FD the client must respond with BEGIN, followed by its stream of messages, or by disconnecting. The server must not accept additional commands using this protocol after the BEGIN command has been received. Further communication will be a stream of D-Bus messages (optionally encrypted, as negotiated) rather than this protocol. Future Extensions Future extensions to the authentication and negotiation protocol are possible. For that new commands may be introduced. If a client or server receives an unknown command it shall respond with ERROR and not consider this fatal. New commands may be introduced both before, and after authentication, i.e. both before and after the OK command. Authentication examples
    Example of successful magic cookie authentication (MAGIC_COOKIE is a made up mechanism) C: AUTH MAGIC_COOKIE 3138363935333137393635383634 S: OK 1234deadbeef C: BEGIN
    Example of finding out mechanisms then picking one C: AUTH S: REJECTED KERBEROS_V4 SKEY C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f S: OK 1234deadbeef C: BEGIN
    Example of client sends unknown command then falls back to regular auth C: FOOBAR S: ERROR C: AUTH MAGIC_COOKIE 3736343435313230333039 S: OK 1234deadbeef C: BEGIN
    Example of server doesn't support initial auth mechanism C: AUTH MAGIC_COOKIE 3736343435313230333039 S: REJECTED KERBEROS_V4 SKEY C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f S: OK 1234deadbeef C: BEGIN
    Example of wrong password or the like followed by successful retry C: AUTH MAGIC_COOKIE 3736343435313230333039 S: REJECTED KERBEROS_V4 SKEY C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f S: REJECTED C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f S: OK 1234deadbeef C: BEGIN
    Example of skey cancelled and restarted C: AUTH MAGIC_COOKIE 3736343435313230333039 S: REJECTED KERBEROS_V4 SKEY C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: CANCEL S: REJECTED C: AUTH SKEY 7ab83f32ee S: DATA 8799cabb2ea93e C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f S: OK 1234deadbeef C: BEGIN
    Example of successful magic cookie authentication with successful negotiation of Unix FD passing (MAGIC_COOKIE is a made up mechanism) C: AUTH MAGIC_COOKIE 3138363935333137393635383634 S: OK 1234deadbeef C: NEGOTIATE_UNIX_FD S: AGREE_UNIX_FD C: BEGIN
    Example of successful magic cookie authentication with unsuccessful negotiation of Unix FD passing (MAGIC_COOKIE is a made up mechanism) C: AUTH MAGIC_COOKIE 3138363935333137393635383634 S: OK 1234deadbeef C: NEGOTIATE_UNIX_FD S: ERROR C: BEGIN
    Authentication state diagrams This section documents the auth protocol in terms of a state machine for the client and the server. This is probably the most robust way to implement the protocol. Client states To more precisely describe the interaction between the protocol state machine and the authentication mechanisms the following notation is used: MECH(CHALL) means that the server challenge CHALL was fed to the mechanism MECH, which returns one of CONTINUE(RESP) means continue the auth conversation and send RESP as the response to the server; OK(RESP) means that after sending RESP to the server the client side of the auth conversation is finished and the server should return "OK"; ERROR means that CHALL was invalid and could not be processed. Both RESP and CHALL may be empty. The Client starts by getting an initial response from the default mechanism and sends AUTH MECH RESP, or AUTH MECH if the mechanism did not provide an initial response. If the mechanism returns CONTINUE, the client starts in state WaitingForData, if the mechanism returns OK the client starts in state WaitingForOK. The client should keep track of available mechanisms and which it mechanisms it has already attempted. This list is used to decide which AUTH command to send. When the list is exhausted, the client should give up and close the connection. <emphasis>WaitingForData</emphasis> Receive DATA CHALL MECH(CHALL) returns CONTINUE(RESP) → send DATA RESP, goto WaitingForData MECH(CHALL) returns OK(RESP) → send DATA RESP, goto WaitingForOK MECH(CHALL) returns ERROR → send ERROR [msg], goto WaitingForData Receive REJECTED [mechs] → send AUTH [next mech], goto WaitingForData or WaitingForOK Receive ERROR → send CANCEL, goto WaitingForReject Receive OK → send BEGIN, terminate auth conversation, authenticated Receive anything else → send ERROR, goto WaitingForData <emphasis>WaitingForOK</emphasis> Receive OK → send BEGIN, terminate auth conversation, authenticated Receive REJECTED [mechs] → send AUTH [next mech], goto WaitingForData or WaitingForOK Receive DATA → send CANCEL, goto WaitingForReject Receive ERROR → send CANCEL, goto WaitingForReject Receive anything else → send ERROR, goto WaitingForOK <emphasis>WaitingForReject</emphasis> Receive REJECTED [mechs] → send AUTH [next mech], goto WaitingForData or WaitingForOK Receive anything else → terminate auth conversation, disconnect Server states For the server MECH(RESP) means that the client response RESP was fed to the the mechanism MECH, which returns one of CONTINUE(CHALL) means continue the auth conversation and send CHALL as the challenge to the client; OK means that the client has been successfully authenticated; REJECTED means that the client failed to authenticate or there was an error in RESP. The server starts out in state WaitingForAuth. If the client is rejected too many times the server must disconnect the client. <emphasis>WaitingForAuth</emphasis> Receive AUTH → send REJECTED [mechs], goto WaitingForAuth Receive AUTH MECH RESP MECH not valid mechanism → send REJECTED [mechs], goto WaitingForAuth MECH(RESP) returns CONTINUE(CHALL) → send DATA CHALL, goto WaitingForData MECH(RESP) returns OK → send OK, goto WaitingForBegin MECH(RESP) returns REJECTED → send REJECTED [mechs], goto WaitingForAuth Receive BEGIN → terminate auth conversation, disconnect Receive ERROR → send REJECTED [mechs], goto WaitingForAuth Receive anything else → send ERROR, goto WaitingForAuth <emphasis>WaitingForData</emphasis> Receive DATA RESP MECH(RESP) returns CONTINUE(CHALL) → send DATA CHALL, goto WaitingForData MECH(RESP) returns OK → send OK, goto WaitingForBegin MECH(RESP) returns REJECTED → send REJECTED [mechs], goto WaitingForAuth Receive BEGIN → terminate auth conversation, disconnect Receive CANCEL → send REJECTED [mechs], goto WaitingForAuth Receive ERROR → send REJECTED [mechs], goto WaitingForAuth Receive anything else → send ERROR, goto WaitingForData <emphasis>WaitingForBegin</emphasis> Receive BEGIN → terminate auth conversation, client authenticated Receive CANCEL → send REJECTED [mechs], goto WaitingForAuth Receive ERROR → send REJECTED [mechs], goto WaitingForAuth Receive anything else → send ERROR, goto WaitingForBegin Authentication mechanisms This section describes some new authentication mechanisms. D-Bus also allows any standard SASL mechanism of course. DBUS_COOKIE_SHA1 The DBUS_COOKIE_SHA1 mechanism is designed to establish that a client has the ability to read a private file owned by the user being authenticated. If the client can prove that it has access to a secret cookie stored in this file, then the client is authenticated. Thus the security of DBUS_COOKIE_SHA1 depends on a secure home directory. Throughout this description, "hex encoding" must output the digits from a to f in lower-case; the digits A to F must not be used in the DBUS_COOKIE_SHA1 mechanism. Authentication proceeds as follows: The client sends the username it would like to authenticate as, hex-encoded. The server sends the name of its "cookie context" (see below); a space character; the integer ID of the secret cookie the client must demonstrate knowledge of; a space character; then a randomly-generated challenge string, all of this hex-encoded into one, single string. The client locates the cookie and generates its own randomly-generated challenge string. The client then concatenates the server's decoded challenge, a ":" character, its own challenge, another ":" character, and the cookie. It computes the SHA-1 hash of this composite string as a hex digest. It concatenates the client's challenge string, a space character, and the SHA-1 hex digest, hex-encodes the result and sends it back to the server. The server generates the same concatenated string used by the client and computes its SHA-1 hash. It compares the hash with the hash received from the client; if the two hashes match, the client is authenticated. Each server has a "cookie context," which is a name that identifies a set of cookies that apply to that server. A sample context might be "org_freedesktop_session_bus". Context names must be valid ASCII, nonzero length, and may not contain the characters slash ("/"), backslash ("\"), space (" "), newline ("\n"), carriage return ("\r"), tab ("\t"), or period ("."). There is a default context, "org_freedesktop_general" that's used by servers that do not specify otherwise. Cookies are stored in a user's home directory, in the directory ~/.dbus-keyrings/. This directory must not be readable or writable by other users. If it is, clients and servers must ignore it. The directory contains cookie files named after the cookie context. A cookie file contains one cookie per line. Each line has three space-separated fields: The cookie ID number, which must be a non-negative integer and may not be used twice in the same file. The cookie's creation time, in UNIX seconds-since-the-epoch format. The cookie itself, a hex-encoded random block of bytes. The cookie may be of any length, though obviously security increases as the length increases. Only server processes modify the cookie file. They must do so with this procedure: Create a lockfile name by appending ".lock" to the name of the cookie file. The server should attempt to create this file using O_CREAT | O_EXCL. If file creation fails, the lock fails. Servers should retry for a reasonable period of time, then they may choose to delete an existing lock to keep users from having to manually delete a stale lock. Lockfiles are used instead of real file locking fcntl() because real locking implementations are still flaky on network filesystems. Once the lockfile has been created, the server loads the cookie file. It should then delete any cookies that are old (the timeout can be fairly short), or more than a reasonable time in the future (so that cookies never accidentally become permanent, if the clock was set far into the future at some point). If no recent keys remain, the server may generate a new key. The pruned and possibly added-to cookie file must be resaved atomically (using a temporary file which is rename()'d). The lock must be dropped by deleting the lockfile. Clients need not lock the file in order to load it, because servers are required to save the file atomically.
    Server Addresses Server addresses consist of a transport name followed by a colon, and then an optional, comma-separated list of keys and values in the form key=value. Each value is escaped. For example: unix:path=/tmp/dbus-test Which is the address to a unix socket with the path /tmp/dbus-test. Value escaping is similar to URI escaping but simpler. The set of optionally-escaped bytes is: [0-9A-Za-z_-/.\]. To escape, each byte (note, not character) which is not in the set of optionally-escaped bytes must be replaced with an ASCII percent (%) and the value of the byte in hex. The hex value must always be two digits, even if the first digit is zero. The optionally-escaped bytes may be escaped if desired. To unescape, append each byte in the value; if a byte is an ASCII percent (%) character then append the following hex value instead. It is an error if a % byte does not have two hex digits following. It is an error if a non-optionally-escaped byte is seen unescaped. The set of optionally-escaped bytes is intended to preserve address readability and convenience. A server may specify a key-value pair with the key guid and the value a hex-encoded 16-byte sequence. describes the format of the guid field. If present, this UUID may be used to distinguish one server address from another. A server should use a different UUID for each address it listens on. For example, if a message bus daemon offers both UNIX domain socket and TCP connections, but treats clients the same regardless of how they connect, those two connections are equivalent post-connection but should have distinct UUIDs to distinguish the kinds of connection. The intent of the address UUID feature is to allow a client to avoid opening multiple identical connections to the same server, by allowing the client to check whether an address corresponds to an already-existing connection. Comparing two addresses is insufficient, because addresses can be recycled by distinct servers, and equivalent addresses may look different if simply compared as strings (for example, the host in a TCP address can be given as an IP address or as a hostname). Note that the address key is guid even though the rest of the API and documentation says "UUID," for historical reasons. [FIXME clarify if attempting to connect to each is a requirement or just a suggestion] When connecting to a server, multiple server addresses can be separated by a semi-colon. The library will then try to connect to the first address and if that fails, it'll try to connect to the next one specified, and so forth. For example unix:path=/tmp/dbus-test;unix:path=/tmp/dbus-test2 Some addresses are connectable. A connectable address is one containing enough information for a client to connect to it. For instance, tcp:host=127.0.0.1,port=4242 is a connectable address. It is not necessarily possible to listen on every connectable address: for instance, it is not possible to listen on a unixexec: address. Some addresses are listenable. A listenable address is one containing enough information for a server to listen on it, producing a connectable address (which may differ from the original address). Many listenable addresses are not connectable: for instance, tcp:host=127.0.0.1 is listenable, but not connectable (because it does not specify a port number). Listening on an address that is not connectable will result in a connectable address that is not the same as the listenable address. For instance, listening on tcp:host=127.0.0.1 might result in the connectable address tcp:host=127.0.0.1,port=30958, listening on unix:tmpdir=/tmp might result in the connectable address unix:abstract=/tmp/dbus-U8OSdmf7, or listening on unix:runtime=yes might result in the connectable address unix:path=/run/user/1234/bus. Transports [FIXME we need to specify in detail each transport and its possible arguments] Current transports include: unix domain sockets (including abstract namespace on linux), launchd, systemd, TCP/IP, an executed subprocess and a debug/testing transport using in-process pipes. Future possible transports include one that tunnels over X11 protocol. Unix Domain Sockets Unix domain sockets can be either paths in the file system or on Linux kernels, they can be abstract which are similar to paths but do not show up in the file system. When a socket is opened by the D-Bus library it truncates the path name right before the first trailing Nul byte. This is true for both normal paths and abstract paths. Note that this is a departure from previous versions of D-Bus that would create sockets with a fixed length path name. Names which were shorter than the fixed length would be padded by Nul bytes. Unix domain sockets are not available on Windows. Unix addresses that specify path or abstract are both listenable and connectable. Unix addresses that specify tmpdir are only listenable: the corresponding connectable address will specify either path or abstract. Similarly, Unix addresses that specify runtime are only listenable, and the corresponding connectable address will specify path. Server Address Format Unix domain socket addresses are identified by the "unix:" prefix and support the following key/value pairs: Name Values Description path (path) path of the unix domain socket. If set, the "tmpdir" and "abstract" key must not be set. tmpdir (path) temporary directory in which a socket file with a random file name starting with 'dbus-' will be created by the server. This key can only be used in server addresses, not in client addresses. If set, the "path" and "abstract" key must not be set. abstract (string) unique string (path) in the abstract namespace. If set, the "path" or "tmpdir" key must not be set. This key is only supported on platforms with "abstract Unix sockets", of which Linux is the only known example. runtime yes If given, This key can only be used in server addresses, not in client addresses. If set, its value must be yes. This is typically used in an address string like unix:runtime=yes;unix:tmpdir=/tmp so that there can be a fallback if XDG_RUNTIME_DIR is not set. Exactly one of the keys path, abstract, runtime or tmpdir must be provided. launchd launchd is an open-source server management system that replaces init, inetd and cron on Apple Mac OS X versions 10.4 and above. It provides a common session bus address for each user and deprecates the X11-enabled D-Bus launcher on OSX. launchd allocates a socket and provides it with the unix path through the DBUS_LAUNCHD_SESSION_BUS_SOCKET variable in launchd's environment. Every process spawned by launchd (or dbus-daemon, if it was started by launchd) can access it through its environment. Other processes can query for the launchd socket by executing: $ launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET This is normally done by the D-Bus client library so doesn't have to be done manually. launchd is not available on Microsoft Windows. launchd addresses are listenable and connectable. Server Address Format launchd addresses are identified by the "launchd:" prefix and support the following key/value pairs: Name Values Description env (environment variable) path of the unix domain socket for the launchd created dbus-daemon. The env key is required. systemd systemd is an open-source server management system that replaces init and inetd on newer Linux systems. It supports socket activation. The D-Bus systemd transport is used to acquire socket activation file descriptors from systemd and use them as D-Bus transport when the current process is spawned by socket activation from it. The systemd transport accepts only one or more Unix domain or TCP streams sockets passed in via socket activation. The systemd transport is not available on non-Linux operating systems. The systemd transport defines no parameter keys. systemd addresses are listenable, but not connectable. The corresponding connectable address is the unix or tcp address of the socket. TCP Sockets The tcp transport provides TCP/IP based connections between clients located on the same or different hosts. Using tcp transport without any additional secure authentification mechanismus over a network is unsecure. On Windows and most Unix platforms, the TCP stack is unable to transfer credentials over a TCP connection, so the EXTERNAL authentication mechanism does not work for this transport. All tcp addresses are listenable. tcp addresses in which both host and port are specified, and port is non-zero, are also connectable. Server Address Format TCP/IP socket addresses are identified by the "tcp:" prefix and support the following key/value pairs: Name Values Description host (string) DNS name or IP address bind (string) Used in a listenable address to configure the interface on which the server will listen: either the IP address of one of the local machine's interfaces (most commonly 127.0.0.1 ), or a DNS name that resolves to one of those IP addresses, or '*' to listen on all interfaces simultaneously. If not specified, the default is the same value as "host". port (number) The tcp port the server will open. A zero value let the server choose a free port provided from the underlaying operating system. libdbus is able to retrieve the real used port from the server. family (string) If set, provide the type of socket family either "ipv4" or "ipv6". If unset, the family is unspecified. Nonce-secured TCP Sockets The nonce-tcp transport provides a secured TCP transport, using a simple authentication mechanism to ensure that only clients with read access to a certain location in the filesystem can connect to the server. The server writes a secret, the nonce, to a file and an incoming client connection is only accepted if the client sends the nonce right after the connect. The nonce mechanism requires no setup and is orthogonal to the higher-level authentication mechanisms described in the Authentication section. On start, the server generates a random 16 byte nonce and writes it to a file in the user's temporary directory. The nonce file location is published as part of the server's D-Bus address using the "noncefile" key-value pair. After an accept, the server reads 16 bytes from the socket. If the read bytes do not match the nonce stored in the nonce file, the server MUST immediately drop the connection. If the nonce match the received byte sequence, the client is accepted and the transport behaves like an unsecured tcp transport. After a successful connect to the server socket, the client MUST read the nonce from the file published by the server via the noncefile= key-value pair and send it over the socket. After that, the transport behaves like an unsecured tcp transport. All nonce-tcp addresses are listenable. nonce-tcp addresses in which host, port and noncefile are all specified, and port is nonzero, are also connectable. Server Address Format Nonce TCP/IP socket addresses uses the "nonce-tcp:" prefix and support the following key/value pairs: Name Values Description host (string) DNS name or IP address bind (string) The same as for tcp: addresses port (number) The tcp port the server will open. A zero value let the server choose a free port provided from the underlaying operating system. libdbus is able to retrieve the real used port from the server. family (string) If set, provide the type of socket family either "ipv4" or "ipv6". If unset, the family is unspecified. noncefile (path) File location containing the secret. This is only meaningful in connectable addresses: a listening D-Bus server that offers this transport will always create a new nonce file. Executed Subprocesses on Unix This transport forks off a process and connects its standard input and standard output with an anonymous Unix domain socket. This socket is then used for communication by the transport. This transport may be used to use out-of-process forwarder programs as basis for the D-Bus protocol. The forked process will inherit the standard error output and process group from the parent process. Executed subprocesses are not available on Windows. unixexec addresses are connectable, but are not listenable. Server Address Format Executed subprocess addresses are identified by the "unixexec:" prefix and support the following key/value pairs: Name Values Description path (path) Path of the binary to execute, either an absolute path or a binary name that is searched for in the default search path of the OS. This corresponds to the first argument of execlp(). This key is mandatory. argv0 (string) The program name to use when executing the binary. If omitted the same value as specified for path= will be used. This corresponds to the second argument of execlp(). argv1, argv2, ... (string) Arguments to pass to the binary. This corresponds to the third and later arguments of execlp(). If a specific argvX is not specified no further argvY for Y > X are taken into account. Meta Transports Meta transports are a kind of transport with special enhancements or behavior. Currently available meta transports include: autolaunch Autolaunch The autolaunch transport provides a way for dbus clients to autodetect a running dbus session bus and to autolaunch a session bus if not present. On Unix, autolaunch addresses are connectable, but not listenable. On Windows, autolaunch addresses are both connectable and listenable. Server Address Format Autolaunch addresses uses the "autolaunch:" prefix and support the following key/value pairs: Name Values Description scope (string) scope of autolaunch (Windows only) "*install-path" - limit session bus to dbus installation path. The dbus installation path is determined from the location of the shared dbus library. If the library is located in a 'bin' subdirectory the installation root is the directory above, otherwise the directory where the library lives is taken as installation root. <install-root>/bin/[lib]dbus-1.dll <install-root>/[lib]dbus-1.dll "*user" - limit session bus to the recent user. other values - specify dedicated session bus like "release", "debug" or other Windows implementation On start, the server opens a platform specific transport, creates a mutex and a shared memory section containing the related session bus address. This mutex will be inspected by the dbus client library to detect a running dbus session bus. The access to the mutex and the shared memory section are protected by global locks. In the recent implementation the autolaunch transport uses a tcp transport on localhost with a port choosen from the operating system. This detail may change in the future. Disclaimer: The recent implementation is in an early state and may not work in all cirumstances and/or may have security issues. Because of this the implementation is not documentated yet. UUIDs A working D-Bus implementation uses universally-unique IDs in two places. First, each server address has a UUID identifying the address, as described in . Second, each operating system kernel instance running a D-Bus client or server has a UUID identifying that kernel, retrieved by invoking the method org.freedesktop.DBus.Peer.GetMachineId() (see ). The term "UUID" in this document is intended literally, i.e. an identifier that is universally unique. It is not intended to refer to RFC4122, and in fact the D-Bus UUID is not compatible with that RFC. The UUID must contain 128 bits of data and be hex-encoded. The hex-encoded string may not contain hyphens or other non-hex-digit characters, and it must be exactly 32 characters long. To generate a UUID, the current reference implementation concatenates 96 bits of random data followed by the 32-bit time in seconds since the UNIX epoch (in big endian byte order). It would also be acceptable and probably better to simply generate 128 bits of random data, as long as the random number generator is of high quality. The timestamp could conceivably help if the random bits are not very random. With a quality random number generator, collisions are extremely unlikely even with only 96 bits, so it's somewhat academic. Implementations should, however, stick to random data for the first 96 bits of the UUID. Standard Interfaces See for details on the notation used in this section. There are some standard interfaces that may be useful across various D-Bus applications. <literal>org.freedesktop.DBus.Peer</literal> The org.freedesktop.DBus.Peer interface has two methods: org.freedesktop.DBus.Peer.Ping () org.freedesktop.DBus.Peer.GetMachineId (out STRING machine_uuid) On receipt of the METHOD_CALL message org.freedesktop.DBus.Peer.Ping, an application should do nothing other than reply with a METHOD_RETURN as usual. It does not matter which object path a ping is sent to. The reference implementation handles this method automatically. On receipt of the METHOD_CALL message org.freedesktop.DBus.Peer.GetMachineId, an application should reply with a METHOD_RETURN containing a hex-encoded UUID representing the identity of the machine the process is running on. This UUID must be the same for all processes on a single system at least until that system next reboots. It should be the same across reboots if possible, but this is not always possible to implement and is not guaranteed. It does not matter which object path a GetMachineId is sent to. The reference implementation handles this method automatically. The UUID is intended to be per-instance-of-the-operating-system, so may represent a virtual machine running on a hypervisor, rather than a physical machine. Basically if two processes see the same UUID, they should also see the same shared memory, UNIX domain sockets, process IDs, and other features that require a running OS kernel in common between the processes. The UUID is often used where other programs might use a hostname. Hostnames can change without rebooting, however, or just be "localhost" - so the UUID is more robust. explains the format of the UUID. <literal>org.freedesktop.DBus.Introspectable</literal> This interface has one method: org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data) Objects instances may implement Introspect which returns an XML description of the object, including its interfaces (with signals and methods), objects below it in the object path tree, and its properties. describes the format of this XML string. <literal>org.freedesktop.DBus.Properties</literal> Many native APIs will have a concept of object properties or attributes. These can be exposed via the org.freedesktop.DBus.Properties interface. org.freedesktop.DBus.Properties.Get (in STRING interface_name, in STRING property_name, out VARIANT value); org.freedesktop.DBus.Properties.Set (in STRING interface_name, in STRING property_name, in VARIANT value); org.freedesktop.DBus.Properties.GetAll (in STRING interface_name, out DICT<STRING,VARIANT> props); It is conventional to give D-Bus properties names consisting of capitalized words without punctuation ("CamelCase"), like member names. For instance, the GObject property connection-status or the Qt property connectionStatus could be represented on D-Bus as ConnectionStatus. Strictly speaking, D-Bus property names are not required to follow the same naming restrictions as member names, but D-Bus property names that would not be valid member names (in particular, GObject-style dash-separated property names) can cause interoperability problems and should be avoided. The available properties and whether they are writable can be determined by calling org.freedesktop.DBus.Introspectable.Introspect, see . An empty string may be provided for the interface name; in this case, if there are multiple properties on an object with the same name, the results are undefined (picking one by according to an arbitrary deterministic rule, or returning an error, are the reasonable possibilities). If one or more properties change on an object, the org.freedesktop.DBus.Properties.PropertiesChanged signal may be emitted (this signal was added in 0.14): org.freedesktop.DBus.Properties.PropertiesChanged (STRING interface_name, DICT<STRING,VARIANT> changed_properties, ARRAY<STRING> invalidated_properties); where changed_properties is a dictionary containing the changed properties with the new values and invalidated_properties is an array of properties that changed but the value is not conveyed. Whether the PropertiesChanged signal is supported can be determined by calling org.freedesktop.DBus.Introspectable.Introspect. Note that the signal may be supported for an object but it may differ how whether and how it is used on a per-property basis (for e.g. performance or security reasons). Each property (or the parent interface) must be annotated with the org.freedesktop.DBus.Property.EmitsChangedSignal annotation to convey this (usually the default value true is sufficient meaning that the annotation does not need to be used). See for details on this annotation. <literal>org.freedesktop.DBus.ObjectManager</literal> An API can optionally make use of this interface for one or more sub-trees of objects. The root of each sub-tree implements this interface so other applications can get all objects, interfaces and properties in a single method call. It is appropriate to use this interface if users of the tree of objects are expected to be interested in all interfaces of all objects in the tree; a more granular API should be used if users of the objects are expected to be interested in a small subset of the objects, a small subset of their interfaces, or both. The method that applications can use to get all objects and properties is GetManagedObjects: org.freedesktop.DBus.ObjectManager.GetManagedObjects (out DICT<OBJPATH,DICT<STRING,DICT<STRING,VARIANT>>> objpath_interfaces_and_properties); The return value of this method is a dict whose keys are object paths. All returned object paths are children of the object path implementing this interface, i.e. their object paths start with the ObjectManager's object path plus '/'. Each value is a dict whose keys are interfaces names. Each value in this inner dict is the same dict that would be returned by the org.freedesktop.DBus.Properties.GetAll() method for that combination of object path and interface. If an interface has no properties, the empty dict is returned. Changes are emitted using the following two signals: org.freedesktop.DBus.ObjectManager.InterfacesAdded (OBJPATH object_path, DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties); org.freedesktop.DBus.ObjectManager.InterfacesRemoved (OBJPATH object_path, ARRAY<STRING> interfaces); The InterfacesAdded signal is emitted when either a new object is added or when an existing object gains one or more interfaces. The InterfacesRemoved signal is emitted whenever an object is removed or it loses one or more interfaces. The second parameter of the InterfacesAdded signal contains a dict with the interfaces and properties (if any) that have been added to the given object path. Similarly, the second parameter of the InterfacesRemoved signal contains an array of the interfaces that were removed. Note that changes on properties on existing interfaces are not reported using this interface - an application should also monitor the existing PropertiesChanged signal on each object. Applications SHOULD NOT export objects that are children of an object (directly or otherwise) implementing this interface but which are not returned in the reply from the GetManagedObjects() method of this interface on the given object. The intent of the ObjectManager interface is to make it easy to write a robust client implementation. The trivial client implementation only needs to make two method calls: org.freedesktop.DBus.AddMatch (bus_proxy, "type='signal',name='org.example.App',path_namespace='/org/example/App'"); objects = org.freedesktop.DBus.ObjectManager.GetManagedObjects (app_proxy); on the message bus and the remote application's ObjectManager, respectively. Whenever a new remote object is created (or an existing object gains a new interface), the InterfacesAdded signal is emitted, and since this signal contains all properties for the interfaces, no calls to the org.freedesktop.Properties interface on the remote object are needed. Additionally, since the initial AddMatch() rule already includes signal messages from the newly created child object, no new AddMatch() call is needed. The org.freedesktop.DBus.ObjectManager interface was added in version 0.17 of the D-Bus specification. Introspection Data Format As described in , objects may be introspected at runtime, returning an XML string that describes the object. The same XML format may be used in other contexts as well, for example as an "IDL" for generating static language bindings. Here is an example of introspection data: <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node name="/com/example/sample_object"> <interface name="com.example.SampleInterface"> <method name="Frobate"> <arg name="foo" type="i" direction="in"/> <arg name="bar" type="s" direction="out"/> <arg name="baz" type="a{us}" direction="out"/> <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> </method> <method name="Bazify"> <arg name="bar" type="(iiu)" direction="in"/> <arg name="bar" type="v" direction="out"/> </method> <method name="Mogrify"> <arg name="bar" type="(iiav)" direction="in"/> </method> <signal name="Changed"> <arg name="new_value" type="b"/> </signal> <property name="Bar" type="y" access="readwrite"/> </interface> <node name="child_of_sample_object"/> <node name="another_child_of_sample_object"/> </node> A more formal DTD and spec needs writing, but here are some quick notes. Only the root <node> element can omit the node name, as it's known to be the object that was introspected. If the root <node> does have a name attribute, it must be an absolute object path. If child <node> have object paths, they must be relative. If a child <node> has any sub-elements, then they must represent a complete introspection of the child. If a child <node> is empty, then it may or may not have sub-elements; the child must be introspected in order to find out. The intent is that if an object knows that its children are "fast" to introspect it can go ahead and return their information, but otherwise it can omit it. The direction element on <arg> may be omitted, in which case it defaults to "in" for method calls and "out" for signals. Signals only allow "out" so while direction may be specified, it's pointless. The possible directions are "in" and "out", unlike CORBA there is no "inout" The possible property access flags are "readwrite", "read", and "write" Multiple interfaces can of course be listed for one <node>. The "name" attribute on arguments is optional. Method, interface, property, and signal elements may have "annotations", which are generic key/value pairs of metadata. They are similar conceptually to Java's annotations and C# attributes. Well-known annotations: Name Values (separated by ,) Description org.freedesktop.DBus.Deprecated true,false Whether or not the entity is deprecated; defaults to false org.freedesktop.DBus.GLib.CSymbol (string) The C symbol; may be used for methods and interfaces org.freedesktop.DBus.Method.NoReply true,false If set, don't expect a reply to the method call; defaults to false. org.freedesktop.DBus.Property.EmitsChangedSignal true,invalidates,const,false If set to false, the org.freedesktop.DBus.Properties.PropertiesChanged signal, see is not guaranteed to be emitted if the property changes. If set to const the property never changes value during the lifetime of the object it belongs to, and hence the signal is never emitted for it. If set to invalidates the signal is emitted but the value is not included in the signal. If set to true the signal is emitted with the value included. The value for the annotation defaults to true if the enclosing interface element does not specify the annotation. Otherwise it defaults to the value specified in the enclosing interface element. This annotation is intended to be used by code generators to implement client-side caching of property values. For all properties for which the annotation is set to const, invalidates or true the client may unconditionally cache the values as the properties don't change or notifications are generated for them if they do. Message Bus Specification Message Bus Overview The message bus accepts connections from one or more applications. Once connected, applications can exchange messages with other applications that are also connected to the bus. In order to route messages among connections, the message bus keeps a mapping from names to connections. Each connection has one unique-for-the-lifetime-of-the-bus name automatically assigned. Applications may request additional names for a connection. Additional names are usually "well-known names" such as "com.example.TextEditor". When a name is bound to a connection, that connection is said to own the name. The bus itself owns a special name, org.freedesktop.DBus, with an object located at /org/freedesktop/DBus that implements the org.freedesktop.DBus interface. This service allows applications to make administrative requests of the bus itself. For example, applications can ask the bus to assign a name to a connection. Each name may have queued owners. When an application requests a name for a connection and the name is already in use, the bus will optionally add the connection to a queue waiting for the name. If the current owner of the name disconnects or releases the name, the next connection in the queue will become the new owner. This feature causes the right thing to happen if you start two text editors for example; the first one may request "com.example.TextEditor", and the second will be queued as a possible owner of that name. When the first exits, the second will take over. Applications may send unicast messages to a specific recipient or to the message bus itself, or broadcast messages to all interested recipients. See for details. Message Bus Names Each connection has at least one name, assigned at connection time and returned in response to the org.freedesktop.DBus.Hello method call. This automatically-assigned name is called the connection's unique name. Unique names are never reused for two different connections to the same bus. Ownership of a unique name is a prerequisite for interaction with the message bus. It logically follows that the unique name is always the first name that an application comes to own, and the last one that it loses ownership of. Unique connection names must begin with the character ':' (ASCII colon character); bus names that are not unique names must not begin with this character. (The bus must reject any attempt by an application to manually request a name beginning with ':'.) This restriction categorically prevents "spoofing"; messages sent to a unique name will always go to the expected connection. When a connection is closed, all the names that it owns are deleted (or transferred to the next connection in the queue if any). A connection can request additional names to be associated with it using the org.freedesktop.DBus.RequestName message. describes the format of a valid name. These names can be released again using the org.freedesktop.DBus.ReleaseName message. <literal>org.freedesktop.DBus.RequestName</literal> As a method: UINT32 RequestName (in STRING name, in UINT32 flags) Message arguments: Argument Type Description 0 STRING Name to request 1 UINT32 Flags Reply arguments: Argument Type Description 0 UINT32 Return value This method call should be sent to org.freedesktop.DBus and asks the message bus to assign the given name to the method caller. Each name maintains a queue of possible owners, where the head of the queue is the primary or current owner of the name. Each potential owner in the queue maintains the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_DO_NOT_QUEUE settings from its latest RequestName call. When RequestName is invoked the following occurs: If the method caller is currently the primary owner of the name, the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_DO_NOT_QUEUE values are updated with the values from the new RequestName call, and nothing further happens. If the current primary owner (head of the queue) has DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, and the RequestName invocation has the DBUS_NAME_FLAG_REPLACE_EXISTING flag, then the caller of RequestName replaces the current primary owner at the head of the queue and the current primary owner moves to the second position in the queue. If the caller of RequestName was in the queue previously its flags are updated with the values from the new RequestName in addition to moving it to the head of the queue. If replacement is not possible, and the method caller is currently in the queue but not the primary owner, its flags are updated with the values from the new RequestName call. If replacement is not possible, and the method caller is currently not in the queue, the method caller is appended to the queue. If any connection in the queue has DBUS_NAME_FLAG_DO_NOT_QUEUE set and is not the primary owner, it is removed from the queue. This can apply to the previous primary owner (if it was replaced) or the method caller (if it updated the DBUS_NAME_FLAG_DO_NOT_QUEUE flag while still stuck in the queue, or if it was just added to the queue with that flag set). Note that DBUS_NAME_FLAG_REPLACE_EXISTING results in "jumping the queue," even if another application already in the queue had specified DBUS_NAME_FLAG_REPLACE_EXISTING. This comes up if a primary owner that does not allow replacement goes away, and the next primary owner does allow replacement. In this case, queued items that specified DBUS_NAME_FLAG_REPLACE_EXISTING do not automatically replace the new primary owner. In other words, DBUS_NAME_FLAG_REPLACE_EXISTING is not saved, it is only used at the time RequestName is called. This is deliberate to avoid an infinite loop anytime two applications are both DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_REPLACE_EXISTING. The flags argument contains any of the following values logically ORed together: Conventional Name Value Description DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 If an application A specifies this flag and succeeds in becoming the owner of the name, and another application B later calls RequestName with the DBUS_NAME_FLAG_REPLACE_EXISTING flag, then application A will lose ownership and receive a org.freedesktop.DBus.NameLost signal, and application B will become the new owner. If DBUS_NAME_FLAG_ALLOW_REPLACEMENT is not specified by application A, or DBUS_NAME_FLAG_REPLACE_EXISTING is not specified by application B, then application B will not replace application A as the owner. DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 Try to replace the current owner if there is one. If this flag is not set the application will only become the owner of the name if there is no current owner. If this flag is set, the application will replace the current owner if the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT. DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 Without this flag, if an application requests a name that is already owned, the application will be placed in a queue to own the name when the current owner gives it up. If this flag is given, the application will not be placed in the queue, the request for the name will simply fail. This flag also affects behavior when an application is replaced as name owner; by default the application moves back into the waiting queue, unless this flag was provided when the application became the name owner. The return code can be one of the following values: Conventional Name Value Description DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 The caller is now the primary owner of the name, replacing any previous owner. Either the name had no owner before, or the caller specified DBUS_NAME_FLAG_REPLACE_EXISTING and the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT. DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 The name already had an owner, DBUS_NAME_FLAG_DO_NOT_QUEUE was not specified, and either the current owner did not specify DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the requesting application did not specify DBUS_NAME_FLAG_REPLACE_EXISTING. DBUS_REQUEST_NAME_REPLY_EXISTS 3 The name already has an owner, DBUS_NAME_FLAG_DO_NOT_QUEUE was specified, and either DBUS_NAME_FLAG_ALLOW_REPLACEMENT was not specified by the current owner, or DBUS_NAME_FLAG_REPLACE_EXISTING was not specified by the requesting application. DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 The application trying to request ownership of a name is already the owner of it. <literal>org.freedesktop.DBus.ReleaseName</literal> As a method: UINT32 ReleaseName (in STRING name) Message arguments: Argument Type Description 0 STRING Name to release Reply arguments: Argument Type Description 0 UINT32 Return value This method call should be sent to org.freedesktop.DBus and asks the message bus to release the method caller's claim to the given name. If the caller is the primary owner, a new primary owner will be selected from the queue if any other owners are waiting. If the caller is waiting in the queue for the name, the caller will removed from the queue and will not be made an owner of the name if it later becomes available. If there are no other owners in the queue for the name, it will be removed from the bus entirely. The return code can be one of the following values: Conventional Name Value Description DBUS_RELEASE_NAME_REPLY_RELEASED 1 The caller has released his claim on the given name. Either the caller was the primary owner of the name, and the name is now unused or taken by somebody waiting in the queue for the name, or the caller was waiting in the queue for the name and has now been removed from the queue. DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 The given name does not exist on this bus. DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 The caller was not the primary owner of this name, and was also not waiting in the queue to own this name. <literal>org.freedesktop.DBus.ListQueuedOwners</literal> As a method: ARRAY of STRING ListQueuedOwners (in STRING name) Message arguments: Argument Type Description 0 STRING The well-known bus name to query, such as com.example.cappuccino Reply arguments: Argument Type Description 0 ARRAY of STRING The unique bus names of connections currently queued for the name This method call should be sent to org.freedesktop.DBus and lists the connections currently queued for a bus name (see ). Message Bus Message Routing Messages may have a DESTINATION field (see ), resulting in a unicast message. If the DESTINATION field is present, it specifies a message recipient by name. Method calls and replies normally specify this field. The message bus must send messages (of any type) with the DESTINATION field set to the specified recipient, regardless of whether the recipient has set up a match rule matching the message. When the message bus receives a signal, if the DESTINATION field is absent, it is considered to be a broadcast signal, and is sent to all applications with message matching rules that match the message. Most signal messages are broadcasts, and no other message types currently defined in this specification may be broadcast. Unicast signal messages (those with a DESTINATION field) are not commonly used, but they are treated like any unicast message: they are delivered to the specified receipient, regardless of its match rules. One use for unicast signals is to avoid a race condition in which a signal is emitted before the intended recipient can call to receive that signal: if the signal is sent directly to that recipient using a unicast message, it does not need to add a match rule at all, and there is no race condition. Another use for unicast signals, on message buses whose security policy prevents eavesdropping, is to send sensitive information which should only be visible to one recipient. When the message bus receives a method call, if the DESTINATION field is absent, the call is taken to be a standard one-to-one message and interpreted by the message bus itself. For example, sending an org.freedesktop.DBus.Peer.Ping message with no DESTINATION will cause the message bus itself to reply to the ping immediately; the message bus will not make this message visible to other applications. Continuing the org.freedesktop.DBus.Peer.Ping example, if the ping message were sent with a DESTINATION name of com.yoyodyne.Screensaver, then the ping would be forwarded, and the Yoyodyne Corporation screensaver application would be expected to reply to the ping. Message bus implementations may impose a security policy which prevents certain messages from being sent or received. When a method call message cannot be sent or received due to a security policy, the message bus should send an error reply, unless the original message had the NO_REPLY flag. Eavesdropping Receiving a unicast message whose DESTINATION indicates a different recipient is called eavesdropping. On a message bus which acts as a security boundary (like the standard system bus), the security policy should usually prevent eavesdropping, since unicast messages are normally kept private and may contain security-sensitive information. Eavesdropping is mainly useful for debugging tools, such as the dbus-monitor tool in the reference implementation of D-Bus. Tools which eavesdrop on the message bus should be careful to avoid sending a reply or error in response to messages intended for a different client. Clients may attempt to eavesdrop by adding match rules (see ) containing the eavesdrop='true' match. If the message bus' security policy does not allow eavesdropping, the match rule can still be added, but will not have any practical effect. For compatibility with older message bus implementations, if adding such a match rule results in an error reply, the client may fall back to adding the same rule with the eavesdrop match omitted. Eavesdropping interacts poorly with buses with non-trivial access control restrictions. The method provides an alternative way to monitor buses. Match Rules An important part of the message bus routing protocol is match rules. Match rules describe the messages that should be sent to a client, based on the contents of the message. Broadcast signals are only sent to clients which have a suitable match rule: this avoids waking up client processes to deal with signals that are not relevant to that client. Messages that list a client as their DESTINATION do not need to match the client's match rules, and are sent to that client regardless. As a result, match rules are mainly used to receive a subset of broadcast signals. Match rules can also be used for eavesdropping (see ), if the security policy of the message bus allows it. Match rules are added using the AddMatch bus method (see ). Rules are specified as a string of comma separated key/value pairs. Excluding a key from the rule indicates a wildcard match. For instance excluding the the member from a match rule but adding a sender would let all messages from that sender through. An example of a complete rule would be "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',path='/bar/foo',destination=':452345.34',arg2='bar'" Within single quotes (ASCII apostrophe, U+0027), a backslash (U+005C) represents itself, and an apostrophe ends the quoted section. Outside single quotes, \' (backslash, apostrophe) represents an apostrophe, and any backslash not followed by an apostrophe represents itself. For instance, the match rules arg0=''\''',arg1='\',arg2=',',arg3='\\' and arg0=\',arg1=\,arg2=',',arg3=\\ both match messages where the arguments are a 1-character string containing an apostrophe, a 1-character string containing a backslash, a 1-character string containing a comma, and a 2-character string containing two backslashes This idiosyncratic quoting style is based on the rules for escaping items to appear inside single-quoted strings in POSIX /bin/sh, but please note that backslashes that are not inside single quotes have different behaviour. This syntax does not offer any way to represent an apostrophe inside single quotes (it is necessary to leave the single-quoted section, backslash-escape the apostrophe and re-enter single quotes), or to represent a comma outside single quotes (it is necessary to wrap it in a single-quoted section). . The following table describes the keys that can be used to create a match rule. Key Possible Values Description type 'signal', 'method_call', 'method_return', 'error' Match on the message type. An example of a type match is type='signal' sender A bus or unique name (see and respectively) Match messages sent by a particular sender. An example of a sender match is sender='org.freedesktop.Hal' interface An interface name (see ) Match messages sent over or to a particular interface. An example of an interface match is interface='org.freedesktop.Hal.Manager'. If a message omits the interface header, it must not match any rule that specifies this key. member Any valid method or signal name Matches messages which have the give method or signal name. An example of a member match is member='NameOwnerChanged' path An object path (see ) Matches messages which are sent from or to the given object. An example of a path match is path='/org/freedesktop/Hal/Manager' path_namespace An object path Matches messages which are sent from or to an object for which the object path is either the given value, or that value followed by one or more path components. For example, path_namespace='/com/example/foo' would match signals sent by /com/example/foo or by /com/example/foo/bar, but not by /com/example/foobar. Using both path and path_namespace in the same match rule is not allowed. This match key was added in version 0.16 of the D-Bus specification and implemented by the bus daemon in dbus 1.5.0 and later. destination A unique name (see ) Matches messages which are being sent to the given unique name. An example of a destination match is destination=':1.0' arg[0, 1, 2, 3, ...] Any string Arg matches are special and are used for further restricting the match based on the arguments in the body of a message. Only arguments of type STRING can be matched in this way. An example of an argument match would be arg3='Foo'. Only argument indexes from 0 to 63 should be accepted. arg[0, 1, 2, 3, ...]path Any string Argument path matches provide a specialised form of wildcard matching for path-like namespaces. They can match arguments whose type is either STRING or OBJECT_PATH. As with normal argument matches, if the argument is exactly equal to the string given in the match rule then the rule is satisfied. Additionally, there is also a match when either the string given in the match rule or the appropriate message argument ends with '/' and is a prefix of the other. An example argument path match is arg0path='/aa/bb/'. This would match messages with first arguments of '/', '/aa/', '/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'. This is intended for monitoring “directories” in file system-like hierarchies, as used in the dconf configuration system. An application interested in all nodes in a particular hierarchy would monitor arg0path='/ca/example/foo/'. Then the service could emit a signal with zeroth argument "/ca/example/foo/bar" to represent a modification to the “bar” property, or a signal with zeroth argument "/ca/example/" to represent atomic modification of many properties within that directory, and the interested application would be notified in both cases. This match key was added in version 0.12 of the D-Bus specification, implemented for STRING arguments by the bus daemon in dbus 1.2.0 and later, and implemented for OBJECT_PATH arguments in dbus 1.5.0 and later. arg0namespace Like a bus name, except that the string is not required to contain a '.' (period) Match messages whose first argument is of type STRING, and is a bus name or interface name within the specified namespace. This is primarily intended for watching name owner changes for a group of related bus names, rather than for a single name or all name changes. Because every valid interface name is also a valid bus name, this can also be used for messages whose first argument is an interface name. For example, the match rule member='NameOwnerChanged',arg0namespace='com.example.backend' matches name owner changes for bus names such as com.example.backend.foo, com.example.backend.foo.bar, and com.example.backend itself. See also . This match key was added in version 0.16 of the D-Bus specification and implemented by the bus daemon in dbus 1.5.0 and later. eavesdrop 'true', 'false' Since D-Bus 1.5.6, match rules do not match messages which have a DESTINATION field unless the match rule specifically requests this (see ) by specifying eavesdrop='true' in the match rule. eavesdrop='false' restores the default behaviour. Messages are delivered to their DESTINATION regardless of match rules, so this match does not affect normal delivery of unicast messages. If the message bus has a security policy which forbids eavesdropping, this match may still be used without error, but will not have any practical effect. In older versions of D-Bus, this match was not allowed in match rules, and all match rules behaved as if eavesdrop='true' had been used. Message Bus Starting Services The message bus can start applications on behalf of other applications. In CORBA terms, this would be called activation. An application that can be started in this way is called a service. With D-Bus, starting a service is normally done by name. That is, applications ask the message bus to start some program that will own a well-known name, such as com.example.TextEditor. This implies a contract documented along with the name com.example.TextEditor for which object the owner of that name will provide, and what interfaces those objects will have. To find an executable corresponding to a particular name, the bus daemon looks for service description files. Service description files define a mapping from names to executables. Different kinds of message bus will look for these files in different places, see . Service description files have the ".service" file extension. The message bus will only load service description files ending with .service; all other files will be ignored. The file format is similar to that of desktop entries. All service description files must be in UTF-8 encoding. To ensure that there will be no name collisions, service files must be namespaced using the same mechanism as messages and service names. On the well-known system bus, the name of a service description file must be its well-known name plus .service, for instance com.example.ConfigurationDatabase.service. On the well-known session bus, services should follow the same service description file naming convention as on the system bus, but for backwards compatibility they are not required to do so. [FIXME the file format should be much better specified than "similar to .desktop entries" esp. since desktop entries are already badly-specified. ;-)] These sections from the specification apply to service files as well: General syntax Comment format Service description files must contain a D-BUS Service group with at least the keys Name (the well-known name of the service) and Exec (the command to be executed).
    Example service description file # Sample service description file [D-BUS Service] Name=com.example.ConfigurationDatabase Exec=/usr/bin/sample-configd
    Additionally, service description files for the well-known system bus on Unix must contain a User key, whose value is the name of a user account (e.g. root). The system service will be run as that user. When an application asks to start a service by name, the bus daemon tries to find a service that will own that name. It then tries to spawn the executable associated with it. If this fails, it will report an error. On the well-known system bus, it is not possible for two .service files in the same directory to offer the same service, because they are constrained to have names that match the service name. On the well-known session bus, if two .service files in the same directory offer the same service name, the result is undefined. Distributors should avoid this situation, for instance by naming session services' .service files according to their service name. If two .service files in different directories offer the same service name, the one in the higher-priority directory is used: for instance, on the system bus, .service files in /usr/local/share/dbus-1/system-services take precedence over those in /usr/share/dbus-1/system-services. The executable launched will have the environment variable DBUS_STARTER_ADDRESS set to the address of the message bus so it can connect and request the appropriate names. The executable being launched may want to know whether the message bus starting it is one of the well-known message buses (see ). To facilitate this, the bus must also set the DBUS_STARTER_BUS_TYPE environment variable if it is one of the well-known buses. The currently-defined values for this variable are system for the systemwide message bus, and session for the per-login-session message bus. The new executable must still connect to the address given in DBUS_STARTER_ADDRESS, but may assume that the resulting connection is to the well-known bus. [FIXME there should be a timeout somewhere, either specified in the .service file, by the client, or just a global value and if the client being activated fails to connect within that timeout, an error should be sent back.] Message Bus Service Scope The "scope" of a service is its "per-", such as per-session, per-machine, per-home-directory, or per-display. The reference implementation doesn't yet support starting services in a different scope from the message bus itself. So e.g. if you start a service on the session bus its scope is per-session. We could add an optional scope to a bus name. For example, for per-(display,session pair), we could have a unique ID for each display generated automatically at login and set on screen 0 by executing a special "set display ID" binary. The ID would be stored in a _DBUS_DISPLAY_ID property and would be a string of random bytes. This ID would then be used to scope names. Starting/locating a service could be done by ID-name pair rather than only by name. Contrast this with a per-display scope. To achieve that, we would want a single bus spanning all sessions using a given display. So we might set a _DBUS_DISPLAY_BUS_ADDRESS property on screen 0 of the display, pointing to this bus.
    Well-known Message Bus Instances Two standard message bus instances are defined here, along with how to locate them and where their service files live. Login session message bus Each time a user logs in, a login session message bus may be started. All applications in the user's login session may interact with one another using this message bus. The address of the login session message bus is given in the DBUS_SESSION_BUS_ADDRESS environment variable. If that variable is not set, applications may also try to read the address from the X Window System root window property _DBUS_SESSION_BUS_ADDRESS. The root window property must have type STRING. The environment variable should have precedence over the root window property. The address of the login session message bus is given in the DBUS_SESSION_BUS_ADDRESS environment variable. If DBUS_SESSION_BUS_ADDRESS is not set, or if it's set to the string "autolaunch:", the system should use platform-specific methods of locating a running D-Bus session server, or starting one if a running instance cannot be found. Note that this mechanism is not recommended for attempting to determine if a daemon is running. It is inherently racy to attempt to make this determination, since the bus daemon may be started just before or just after the determination is made. Therefore, it is recommended that applications do not try to make this determination for their functionality purposes, and instead they should attempt to start the server. X Windowing System For the X Windowing System, the application must locate the window owner of the selection represented by the atom formed by concatenating: the literal string "_DBUS_SESSION_BUS_SELECTION_" the current user's username the literal character '_' (underscore) the machine's ID The following properties are defined for the window that owns this X selection: Atom meaning _DBUS_SESSION_BUS_ADDRESS the actual address of the server socket _DBUS_SESSION_BUS_PID the PID of the server process At least the _DBUS_SESSION_BUS_ADDRESS property MUST be present in this window. If the X selection cannot be located or if reading the properties from the window fails, the implementation MUST conclude that there is no D-Bus server running and proceed to start a new server. (See below on concurrency issues) Failure to connect to the D-Bus server address thus obtained MUST be treated as a fatal connection error and should be reported to the application. As an alternative, an implementation MAY find the information in the following file located in the current user's home directory, in subdirectory .dbus/session-bus/: the machine's ID the literal character '-' (dash) the X display without the screen number, with the following prefixes removed, if present: ":", "localhost:" ."localhost.localdomain:". That is, a display of "localhost:10.0" produces just the number "10" The contents of this file NAME=value assignment pairs and lines starting with # are comments (no comments are allowed otherwise). The following variable names are defined: Variable meaning DBUS_SESSION_BUS_ADDRESS the actual address of the server socket DBUS_SESSION_BUS_PID the PID of the server process DBUS_SESSION_BUS_WINDOWID the window ID At least the DBUS_SESSION_BUS_ADDRESS variable MUST be present in this file. Failure to open this file MUST be interpreted as absence of a running server. Therefore, the implementation MUST proceed to attempting to launch a new bus server if the file cannot be opened. However, success in opening this file MUST NOT lead to the conclusion that the server is running. Thus, a failure to connect to the bus address obtained by the alternative method MUST NOT be considered a fatal error. If the connection cannot be established, the implementation MUST proceed to check the X selection settings or to start the server on its own. If the implementation concludes that the D-Bus server is not running it MUST attempt to start a new server and it MUST also ensure that the daemon started as an effect of the "autolaunch" mechanism provides the lookup mechanisms described above, so subsequent calls can locate the newly started server. The implementation MUST also ensure that if two or more concurrent initiations happen, only one server remains running and all other initiations are able to obtain the address of this server and connect to it. In other words, the implementation MUST ensure that the X selection is not present when it attempts to set it, without allowing another process to set the selection between the verification and the setting (e.g., by using XGrabServer / XungrabServer). On Unix systems, the session bus should search for .service files in $XDG_DATA_DIRS/dbus-1/services as defined by the XDG Base Directory Specification. Implementations may also search additional locations, which should be searched with lower priority than anything in XDG_DATA_HOME, XDG_DATA_DIRS or their respective defaults; for example, the reference implementation also looks in ${datadir}/dbus-1/services as set at compile time. As described in the XDG Base Directory Specification, software packages should install their session .service files to their configured ${datadir}/dbus-1/services, where ${datadir} is as defined by the GNU coding standards. System administrators or users can arrange for these service files to be read by setting XDG_DATA_DIRS or by symlinking them into the default locations. System message bus A computer may have a system message bus, accessible to all applications on the system. This message bus may be used to broadcast system events, such as adding new hardware devices, changes in the printer queue, and so forth. The address of the system message bus is given in the DBUS_SYSTEM_BUS_ADDRESS environment variable. If that variable is not set, applications should try to connect to the well-known address unix:path=/var/run/dbus/system_bus_socket. The D-Bus reference implementation actually honors the $(localstatedir) configure option for this address, on both client and server side. On Unix systems, the system bus should default to searching for .service files in /usr/local/share/dbus-1/system-services, /usr/share/dbus-1/system-services and /lib/dbus-1/system-services, with that order of precedence. It may also search other implementation-specific locations, but should not vary these locations based on environment variables. The system bus is security-sensitive and is typically executed by an init system with a clean environment. Its launch helper process is particularly security-sensitive, and specifically clears its own environment. Software packages should install their system .service files to their configured ${datadir}/dbus-1/system-services, where ${datadir} is as defined by the GNU coding standards. System administrators can arrange for these service files to be read by editing the system bus' configuration file or by symlinking them into the default locations. Message Bus Messages The special message bus name org.freedesktop.DBus responds to a number of additional messages. <literal>org.freedesktop.DBus.Hello</literal> As a method: STRING Hello () Reply arguments: Argument Type Description 0 STRING Unique name assigned to the connection Before an application is able to send messages to other applications it must send the org.freedesktop.DBus.Hello message to the message bus to obtain a unique name. If an application without a unique name tries to send a message to another application, or a message to the message bus itself that isn't the org.freedesktop.DBus.Hello message, it will be disconnected from the bus. There is no corresponding "disconnect" request; if a client wishes to disconnect from the bus, it simply closes the socket (or other communication channel). <literal>org.freedesktop.DBus.ListNames</literal> As a method: ARRAY of STRING ListNames () Reply arguments: Argument Type Description 0 ARRAY of STRING Array of strings where each string is a bus name Returns a list of all currently-owned names on the bus. <literal>org.freedesktop.DBus.ListActivatableNames</literal> As a method: ARRAY of STRING ListActivatableNames () Reply arguments: Argument Type Description 0 ARRAY of STRING Array of strings where each string is a bus name Returns a list of all names that can be activated on the bus. <literal>org.freedesktop.DBus.NameHasOwner</literal> As a method: BOOLEAN NameHasOwner (in STRING name) Message arguments: Argument Type Description 0 STRING Name to check Reply arguments: Argument Type Description 0 BOOLEAN Return value, true if the name exists Checks if the specified name exists (currently has an owner). <literal>org.freedesktop.DBus.NameOwnerChanged</literal> This is a signal: NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner) Message arguments: Argument Type Description 0 STRING Name with a new owner 1 STRING Old owner or empty string if none 2 STRING New owner or empty string if none This signal indicates that the owner of a name has changed. It's also the signal to use to detect the appearance of new names on the bus. <literal>org.freedesktop.DBus.NameLost</literal> This is a signal: NameLost (STRING name) Message arguments: Argument Type Description 0 STRING Name which was lost This signal is sent to a specific application when it loses ownership of a name. <literal>org.freedesktop.DBus.NameAcquired</literal> This is a signal: NameAcquired (STRING name) Message arguments: Argument Type Description 0 STRING Name which was acquired This signal is sent to a specific application when it gains ownership of a name. <literal>org.freedesktop.DBus.StartServiceByName</literal> As a method: UINT32 StartServiceByName (in STRING name, in UINT32 flags) Message arguments: Argument Type Description 0 STRING Name of the service to start 1 UINT32 Flags (currently not used) Reply arguments: Argument Type Description 0 UINT32 Return value Tries to launch the executable associated with a name. For more information, see . The return value can be one of the following values: Identifier Value Description DBUS_START_REPLY_SUCCESS 1 The service was successfully started. DBUS_START_REPLY_ALREADY_RUNNING 2 A connection already owns the given name. <literal>org.freedesktop.DBus.UpdateActivationEnvironment</literal> As a method: UpdateActivationEnvironment (in ARRAY of DICT<STRING,STRING> environment) Message arguments: Argument Type Description 0 ARRAY of DICT<STRING,STRING> Environment to add or update Normally, session bus activated services inherit the environment of the bus daemon. This method adds to or modifies that environment when activating services. Some bus instances, such as the standard system bus, may disable access to this method for some or all callers. Note, both the environment variable names and values must be valid UTF-8. There's no way to update the activation environment with data that is invalid UTF-8. <literal>org.freedesktop.DBus.GetNameOwner</literal> As a method: STRING GetNameOwner (in STRING name) Message arguments: Argument Type Description 0 STRING Name to get the owner of Reply arguments: Argument Type Description 0 STRING Return value, a unique connection name Returns the unique connection name of the primary owner of the name given. If the requested name doesn't have an owner, returns a org.freedesktop.DBus.Error.NameHasNoOwner error. <literal>org.freedesktop.DBus.GetConnectionUnixUser</literal> As a method: UINT32 GetConnectionUnixUser (in STRING bus_name) Message arguments: Argument Type Description 0 STRING Unique or well-known bus name of the connection to query, such as :12.34 or com.example.tea Reply arguments: Argument Type Description 0 UINT32 Unix user ID Returns the Unix user ID of the process connected to the server. If unable to determine it (for instance, because the process is not on the same machine as the bus daemon), an error is returned. <literal>org.freedesktop.DBus.GetConnectionUnixProcessID</literal> As a method: UINT32 GetConnectionUnixProcessID (in STRING bus_name) Message arguments: Argument Type Description 0 STRING Unique or well-known bus name of the connection to query, such as :12.34 or com.example.tea Reply arguments: Argument Type Description 0 UINT32 Unix process id Returns the Unix process ID of the process connected to the server. If unable to determine it (for instance, because the process is not on the same machine as the bus daemon), an error is returned. <literal>org.freedesktop.DBus.GetConnectionCredentials</literal> As a method: DICT<STRING,VARIANT> GetConnectionCredentials (in STRING bus_name) Message arguments: Argument Type Description 0 STRING Unique or well-known bus name of the connection to query, such as :12.34 or com.example.tea Reply arguments: Argument Type Description 0 DICT<STRING,VARIANT> Credentials Returns as many credentials as possible for the process connected to the server. If unable to determine certain credentials (for instance, because the process is not on the same machine as the bus daemon, or because this version of the bus daemon does not support a particular security framework), or if the values of those credentials cannot be represented as documented here, then those credentials are omitted. Keys in the returned dictionary not containing "." are defined by this specification. Bus daemon implementors supporting credentials frameworks not mentioned in this document should either contribute patches to this specification, or use keys containing "." and starting with a reversed domain name. Key Value type Value UnixUserID UINT32 The numeric Unix user ID, as defined by POSIX ProcessID UINT32 The numeric process ID, on platforms that have this concept. On Unix, this is the process ID defined by POSIX. WindowsSID STRING The Windows security identifier in its string form, e.g. "S-1-5-21-3623811015-3361044348-30300820-1013" for a domain or local computer user or "S-1-5-18" for the LOCAL_SYSTEM user LinuxSecurityLabel ARRAY of BYTE On Linux systems, the security label that would result from the SO_PEERSEC getsockopt call. The array contains the non-zero bytes of the security label in an unspecified ASCII-compatible encoding It could be ASCII or UTF-8, but could also be ISO Latin-1 or any other encoding. , followed by a single zero byte. For example, the SELinux context system_u:system_r:init_t:s0 (a string of length 27) would be encoded as 28 bytes ending with ':', 's', '0', '\x00'. Note that this is not the same as the older GetConnectionSELinuxContext method, which does not append the zero byte. Always appending the zero byte allows callers to read the string from the message payload without copying. On SELinux systems this is the SELinux context, as output by ps -Z or ls -Z. Typical values might include system_u:system_r:init_t:s0, unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023, or unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023. On Smack systems, this is the Smack label. Typical values might include _, *, User, System or System::Shared. On AppArmor systems, this is the AppArmor context, a composite string encoding the AppArmor label (one or more profiles) and the enforcement mode. Typical values might include unconfined, /usr/bin/firefox (enforce) or user1 (complain). This method was added in D-Bus 1.7 to reduce the round-trips required to list a process's credentials. In older versions, calling this method will fail: applications should recover by using the separate methods such as instead. <literal>org.freedesktop.DBus.GetAdtAuditSessionData</literal> As a method: ARRAY of BYTE GetAdtAuditSessionData (in STRING bus_name) Message arguments: Argument Type Description 0 STRING Unique or well-known bus name of the connection to query, such as :12.34 or com.example.tea Reply arguments: Argument Type Description 0 ARRAY of BYTE auditing data as returned by adt_export_session_data() Returns auditing data used by Solaris ADT, in an unspecified binary format. If you know what this means, please contribute documentation via the D-Bus bug tracking system. This method is on the core DBus interface for historical reasons; the same information should be made available via in future. <literal>org.freedesktop.DBus.GetConnectionSELinuxSecurityContext</literal> As a method: ARRAY of BYTE GetConnectionSELinuxSecurityContext (in STRING bus_name) Message arguments: Argument Type Description 0 STRING Unique or well-known bus name of the connection to query, such as :12.34 or com.example.tea Reply arguments: Argument Type Description 0 ARRAY of BYTE some sort of string of bytes, not necessarily UTF-8, not including '\0' Returns the security context used by SELinux, in an unspecified format. If you know what this means, please contribute documentation via the D-Bus bug tracking system. This method is on the core DBus interface for historical reasons; the same information should be made available via in future. <literal>org.freedesktop.DBus.AddMatch</literal> As a method: AddMatch (in STRING rule) Message arguments: Argument Type Description 0 STRING Match rule to add to the connection Adds a match rule to match messages going through the message bus (see ). If the bus does not have enough resources the org.freedesktop.DBus.Error.OOM error is returned. <literal>org.freedesktop.DBus.RemoveMatch</literal> As a method: RemoveMatch (in STRING rule) Message arguments: Argument Type Description 0 STRING Match rule to remove from the connection Removes the first rule that matches (see ). If the rule is not found the org.freedesktop.DBus.Error.MatchRuleNotFound error is returned. <literal>org.freedesktop.DBus.GetId</literal> As a method: GetId (out STRING id) Reply arguments: Argument Type Description 0 STRING Unique ID identifying the bus daemon Gets the unique ID of the bus. The unique ID here is shared among all addresses the bus daemon is listening on (TCP, UNIX domain socket, etc.) and its format is described in . Each address the bus is listening on also has its own unique ID, as described in . The per-bus and per-address IDs are not related. There is also a per-machine ID, described in and returned by org.freedesktop.DBus.Peer.GetMachineId(). For a desktop session bus, the bus ID can be used as a way to uniquely identify a user's session. <literal>org.freedesktop.DBus.Monitoring.BecomeMonitor</literal> As a method: BecomeMonitor (in ARRAY of STRING rule, in UINT32 flags) Message arguments: Argument Type Description 0 ARRAY of STRING Match rules to add to the connection 1 UINT32 Not used, must be 0 Converts the connection into a monitor connection which can be used as a debugging/monitoring tool. Only a user who is privileged on this bus (by some implementation-specific definition) may create monitor connections In the reference implementation, the default configuration is that each user (identified by numeric user ID) may monitor their own session bus, and the root user (user ID zero) may monitor the system bus. . Monitor connections lose all their bus names, including the unique connection name, and all their match rules. Sending messages on a monitor connection is not allowed: applications should use a private connection for monitoring. Monitor connections may receive all messages, even messages that should only have gone to some other connection ("eavesdropping"). The first argument is a list of match rules, which replace any match rules that were previously active for this connection. These match rules are always treated as if they contained the special eavesdrop='true' member. As a special case, an empty list of match rules (which would otherwise match nothing, making the monitor useless) is treated as a shorthand for matching all messages. The second argument might be used for flags to influence the behaviour of the monitor connection in future D-Bus versions. Message bus implementations should attempt to minimize the side-effects of monitoring — in particular, unlike ordinary eavesdropping, monitoring the system bus does not require the access control rules to be relaxed, which would change the set of messages that can be delivered to their (non-monitor) destinations. However, it is unavoidable that monitoring will increase the message bus's resource consumption. In edge cases where there was barely enough time or memory without monitoring, this might result in message deliveries failing when they would otherwise have succeeded.
    Glossary This glossary defines some of the terms used in this specification. Bus Name The message bus maintains an association between names and connections. (Normally, there's one connection per application.) A bus name is simply an identifier used to locate connections. For example, the hypothetical com.yoyodyne.Screensaver name might be used to send a message to a screensaver from Yoyodyne Corporation. An application is said to own a name if the message bus has associated the application's connection with the name. Names may also have queued owners (see ). The bus assigns a unique name to each connection, see . Other names can be thought of as "well-known names" and are used to find applications that offer specific functionality. See for details of the syntax and naming conventions for bus names. Message A message is the atomic unit of communication via the D-Bus protocol. It consists of a header and a body; the body is made up of arguments. Message Bus The message bus is a special application that forwards or routes messages between a group of applications connected to the message bus. It also manages names used for routing messages. Name See . "Name" may also be used to refer to some of the other names in D-Bus, such as interface names. Namespace Used to prevent collisions when defining new interfaces, bus names etc. The convention used is the same one Java uses for defining classes: a reversed domain name. See , , , . Object Each application contains objects, which have interfaces and methods. Objects are referred to by a name, called a path. One-to-One An application talking directly to another application, without going through a message bus. One-to-one connections may be "peer to peer" or "client to server." The D-Bus protocol has no concept of client vs. server after a connection has authenticated; the flow of messages is symmetrical (full duplex). Path Object references (object names) in D-Bus are organized into a filesystem-style hierarchy, so each object is named by a path. As in LDAP, there's no difference between "files" and "directories"; a path can refer to an object, while still having child objects below it. Queued Name Owner Each bus name has a primary owner; messages sent to the name go to the primary owner. However, certain names also maintain a queue of secondary owners "waiting in the wings." If the primary owner releases the name, then the first secondary owner in the queue automatically becomes the new owner of the name. Service A service is an executable that can be launched by the bus daemon. Services normally guarantee some particular features, for example they may guarantee that they will request a specific name such as "com.example.Screensaver", have a singleton object "/com/example/Application", and that object will implement the interface "com.example.Screensaver.Control". Service Description Files ".service files" tell the bus about service applications that can be launched (see ). Most importantly they provide a mapping from bus names to services that will request those names when they start up. Unique Connection Name The special name automatically assigned to each connection by the message bus. This name will never change owner, and will be unique (never reused during the lifetime of the message bus). It will begin with a ':' character.
    dbus-1.10.6/doc/dbus-faq.xml0000644000175000017500000006577012602773110015545 0ustar00smcvsmcv00000000000000
    D-Bus FAQ Version 0.3 17 November 2006 Havoc Pennington Red Hat, Inc.
    hp@pobox.com
    David A Wheeler
    What is D-Bus? This is probably best answered by reading the D-Bus tutorial or the introduction to the specification. In short, it is a system consisting of 1) a wire protocol for exposing a typical object-oriented language/framework to other applications; and 2) a bus daemon that allows applications to find and monitor one another. Phrased differently, D-Bus is 1) an interprocess communication (IPC) system and 2) some higher-level structure (lifecycle tracking, service activation, security policy) provided by two bus daemons, one systemwide and one per-user-session. Is D-Bus stable/finished? The low-level library "libdbus" and the protocol specification are considered ABI stable. The README file has a discussion of the API/ABI stability guarantees. Higher-level bindings (such as those for Qt, GLib, Python, Java, C#) each have their own release schedules and degree of maturity, not linked to the low-level library and bus daemon release. Check the project page for the binding you're considering to understand that project's policies. How is the reference implementation licensed? Can I use it in proprietary applications? The short answer is yes, you can use it in proprietary applications. You should read the COPYING file, which offers you the choice of two licenses. These are the GPL and the AFL. The GPL requires that your application be licensed under the GPL as well. The AFL is an "X-style" or "BSD-style" license compatible with proprietary licensing, but it does have some requirements; in particular it prohibits you from filing a lawsuit alleging that the D-Bus software infringes your patents while you continue to use D-Bus. If you're going to sue, you have to stop using the software. Read the licenses to determine their meaning, this FAQ entry is not intended to change the meaning or terms of the licenses. What is the difference between a bus name, and object path, and an interface? If you imagine a C++ program that implements a network service, then the bus name is the hostname of the computer running this C++ program, the object path is a C++ object instance pointer, and an interface is a C++ class (a pure virtual or abstract class, to be exact). In Java terms, the object path is an object reference, and an interface is a Java interface. People get confused because if they write an application with a single object instance and a single interface, then the bus name, object path, and interface look redundant. For example, you might have a text editor that uses the bus name org.freedesktop.TextEditor, has a global singleton object called /org/freedesktop/TextEditor, and that singleton object could implement the interface org.freedesktop.TextEditor. However, a text editor application could as easily own multiple bus names (for example, org.kde.KWrite in addition to generic TextEditor), have multiple objects (maybe /org/kde/documents/4352 where the number changes according to the document), and each object could implement multiple interfaces, such as org.freedesktop.DBus.Introspectable, org.freedesktop.BasicTextField, org.kde.RichTextDocument. What is a "service"? A service is a program that can be launched by the bus daemon to provide some functionality to other programs. Services are normally launched according to the bus name they will have. People often misuse the word "service" for any bus name, but this tends to be ambiguous and confusing so is discouraged. In the D-Bus docs we try to use "service" only when talking about programs the bus knows how to launch, i.e. a service always has a .service file. Is D-Bus a "component system"? It helps to keep these concepts separate in your mind: Object/component system GUI control/widget embedding interfaces Interprocess communication system or wire protocol D-Bus is not a component system. "Component system" was originally defined by COM, and was essentially a workaround for the limitations of the C++ object system (adding introspection, runtime location of objects, ABI guarantees, and so forth). With the C# language and CLR, Microsoft added these features to the primary object system, leaving COM obsolete. Similarly, Java has much less need for something like COM than C++ did. Even QObject (from Qt) and GObject (from GLib) offer some of the same features found in COM. Component systems are not about GUI control embedding. Embedding a spreadsheet in a word processor document is a matter of defining some specific interfaces that objects can implement. These interfaces provide methods related to GUI controls. So an object implementing those interfaces can be embedded. The word "component" just means "object with some fancy features" and in modern languages all objects are effectively "components." So components are fancy objects, and some objects are GUI controls. A third, unrelated feature is interprocess communication or IPC. D-Bus is an IPC system. Given an object (or "component" if you must), you can expose the functionality of that object over an IPC system. Examples of IPC systems are DCOM, CORBA, SOAP, XML-RPC, and D-Bus. You can use any of these IPC systems with any object/component system, though some of them are "tuned" for specific object systems. You can think of an IPC system primarily as a wire protocol. If you combine an IPC system with a set of GUI control interfaces, then you can have an out-of-process or dynamically-loaded GUI control. Another related concept is the plugin or extension. Generic plugin systems such as the Eclipse system are not so different from component/object systems, though perhaps a "plugin" tends to be a bundle of objects with a user-visible name and can be downloaded/packaged as a unit. How fast is the D-Bus reference implementation? Of course it depends a bit on what you're doing. This mail contains some benchmarking. At the time of that benchmark, D-Bus one-to-one communication was about 2.5x slower than simply pushing the data raw over a socket. After the recent rewrite of the marshaling code, D-Bus is slower than that because a lot of optimization work was lost. But it can probably be sped up again. D-Bus communication with the intermediate bus daemon should be (and as last profiled, was) about twice as slow as one-to-one mode, because a round trip involves four socket reads/writes rather than two socket reads/writes. The overhead comes from a couple of places; part of it is simply "abstraction penalty" (there are layers of code to support multiple main loops, multiple transport types, security, etc.). Probably the largest part comes from data validation (because the reference implementation does not trust incoming data). It would be simple to add a "no validation" mode, but probably not a good idea all things considered. Raw bandwidth isn't the only concern; D-Bus is designed to enable asynchronous communication and avoid round trips. This is frequently a more important performance issue than throughput. How large is the D-Bus reference implementation? A production build (with assertions, unit tests, and verbose logging disabled) is on the order of a 150K shared library. A much, much smaller implementation would be possible by omitting out of memory handling, hardcoding a main loop (or always using blocking I/O), skipping validation, and otherwise simplifying things. How does D-Bus differ from other interprocess communication or networking protocols? Keep in mind, it is not only an IPC system; it also includes lifecycle tracking, service activation, security policy, and other higher-level structure and assumptions. The best place to start is to read the D-Bus tutorial, so you have a concrete idea what D-Bus actually is. If you understand other protocols on a wire format level, you may also want to read the D-Bus specification to see what D-Bus looks like on a low level. As the tutorial and specification both explain, D-Bus is tuned for some specific use cases. Thus, it probably isn't tuned for what you want to do, unless you are doing the things D-Bus was designed for. Don't make the mistake of thinking that any system involving "IPC" is the same thing. The D-Bus authors would not recommend using D-Bus for applications where it doesn't make sense. The following questions compare D-Bus to some other protocols primarily to help you understand D-Bus and decide whether it's appropriate; D-Bus is neither intended nor claimed to be the right choice for every application. It should be possible to bridge D-Bus to other IPC systems, just as D-Bus can be bridged to object systems. Note: the D-Bus mailing list subscribers are very much not interested in debating which IPC system is the One True System. So if you want to discuss that, please use another forum. How does D-Bus differ from CORBA? Start by reading . CORBA is designed to support object-oriented IPC between objects, automatically marshalling parameters as necessary. CORBA is strongly supported by the Open Management Group (OMG), which produces various standards and supporting documents for CORBA and has the backing of many large organizations. There are many CORBA ORBs available, both proprietary ORBs and free / open source software ORBs (the latter include ORBit, MICO, and The ACE Orb (TAO)). Many organizations continue to use CORBA ORBs for various kinds of IPC. Both GNOME and KDE have used CORBA and then moved away from it. KDE had more success with a system called DCOP, and GNOME layered a system called Bonobo on top of CORBA. Without custom extensions, CORBA does not support many of the things one wants to do in a desktop environment with the GNOME/KDE architecture. CORBA on the other hand has a number of features of interest for enterprise and web application development, though XML systems such as SOAP are the latest fad. Like D-Bus, CORBA uses a fast binary protocol (IIOP). Both systems work in terms of objects and methods, and have concepts such as "oneway" calls. Only D-Bus has direct support for "signals" as in GLib/Qt (or Java listeners, or C# delegates). D-Bus hardcodes and specifies a lot of things that CORBA leaves open-ended, because CORBA is more generic and D-Bus has two specific use-cases in mind. This makes D-Bus a bit simpler. However, unlike CORBA D-Bus does not specify the API for the language bindings. Instead, "native" bindings adapted specifically to the conventions of a framework such as QObject, GObject, C#, Java, Python, etc. are encouraged. The libdbus reference implementation is designed to be a backend for bindings of this nature, rather than to be used directly. The rationale is that an IPC system API should not "leak" all over a program; it should come into play only just before data goes over the wire. As an aside, OMG is apparently working on a simpler C++ binding for CORBA. Many CORBA implementations such as ORBit are faster than the libdbus reference implementation. One reason is that D-Bus considers data from the other end of the connection to be untrusted and extensively validates it. But generally speaking other priorities were placed ahead of raw speed in the libdbus implementation. A fast D-Bus implementation along the lines of ORBit should be possible, of course. On a more trivial note, D-Bus involves substantially fewer acronyms than CORBA. How does D-Bus differ from XML-RPC and SOAP? Start by reading . In SOAP and XML-RPC, RPC calls are transformed into an XML-based format, then sent over the wire (typically using the HTTP protocol), where they are processed and returned. XML-RPC is the simple protocol (its spec is only a page or two), and SOAP is the full-featured protocol. XML-RPC and SOAP impose XML parsing overhead that is normally irrelevant in the context of the Internet, but significant for constant fine-grained IPC among applications in a desktop session. D-Bus offers persistent connections and with the bus daemon supports lifecycle tracking of other applications connected to the bus. With XML-RPC and SOAP, typically each method call exists in isolation and has its own HTTP connection. How does D-Bus differ from DCE? Start by reading . Distributed Computing Environment (DCE) is an industry-standard vendor-neutral standard that includes an IPC mechanism. The Open Group has released an implementation as open source software. DCE is quite capable, and includes a vast amount of functionality such as a distributed time service. As the name implies, DCE is intended for use in a large, multi-computer distributed application. D-Bus would not be well-suited for this. How does D-Bus differ from DCOM and COM? Start by reading . Comparing D-Bus to COM is apples and oranges; see . DCOM (distributed COM) is a Windows IPC system designed for use with the COM object system. It's similar in some ways to DCE and CORBA. How does D-Bus differ from ZeroC's Internet Communications Engine (Ice) Start by reading . The Internet Communications Engine (Ice) is a powerful IPC mechanism more on the level of SOAP or CORBA than D-Bus. Ice has a "dual-license" business around it; i.e. you can use it under the GPL, or pay for a proprietary license. How does D-Bus differ from Inter-Client Exchange (ICE)? ICE was developed for the X Session Management protocol (XSMP), as part of the X Window System (X11R6.1). The idea was to allow desktop sessions to contain nongraphical clients in addition to X clients. ICE is a binary protocol designed for desktop use, and KDE's DCOP builds on ICE. ICE is substantially simpler than D-Bus (in contrast to most of the other IPC systems mentioned here, which are more complex). ICE doesn't really define a mapping to objects and methods (DCOP adds that layer). The reference implementation of ICE (libICE) is often considered to be horrible (and horribly insecure). DCOP and XSMP are the only two widely-used applications of ICE, and both could in principle be replaced by D-Bus. (Though whether GNOME and KDE will bother is an open question.) How does D-Bus differ from DCOP? Start by reading . D-Bus is intentionally pretty similar to DCOP, and can be thought of as a "DCOP the next generation" suitable for sharing between the various open source desktop projects. D-Bus is a bit more complex than DCOP, though the Qt binding for D-Bus should not be more complex for programmers. The additional complexity of D-Bus arises from its separation of object references vs. bus names vs. interfaces as distinct concepts, and its support for one-to-one connections in addition to connections over the bus. The libdbus reference implementation has a lot of API to support multiple bindings and main loops, and performs data validation and out-of-memory handling in order to support secure applications such as the systemwide bus. D-Bus is probably somewhat slower than DCOP due to data validation and more "layers" in the reference implementation. A comparison hasn't been posted to the list though. At this time, KDE has not committed to using D-Bus, but there have been discussions of KDE bridging D-Bus and DCOP, or even changing DCOP's implementation to use D-Bus internally (so that GNOME and KDE would end up using exactly the same bus). See the KDE mailing list archives for some of these discussions. How does D-Bus differ from [yet more IPC mechanisms]? Start by reading . There are countless uses of network sockets in the world. MBUS, Sun ONC/RPC, Jabber/XMPP, SIP, are some we can think of quickly. Which IPC mechanism should I use? Start by reading . If you're writing an Internet or Intranet application, XML-RPC or SOAP work for many people. These are standard, available for most languages, simple to debug and easy to use. If you're writing a desktop application for UNIX, then D-Bus is of course our recommendation for talking to other parts of the desktop session. D-Bus is also designed for communications between system daemons and communications between the desktop and system daemons. If you're doing something complicated such as clustering, distributed swarms, peer-to-peer, or whatever then the authors of this FAQ don't have expertise in these areas and you should ask someone else or try a search engine. D-Bus is most likely a poor choice but could be appropriate for some things. Note: the D-Bus mailing list is probably not the place to discuss which system is appropriate for your application, though you are welcome to ask specific questions about D-Bus after reading this FAQ, the tutorial, and searching the list archives. The best way to search the list archives is probably to use an Internet engine such as Google. On Google, include "site:freedesktop.org" in your search. How can I submit a bug or patch? The D-Bus web site has a link to the bug tracker, which is the best place to store patches. You can also post them to the list, especially if you want to discuss the patch or get feedback.
    dbus-1.10.6/doc/doxygen_to_devhelp.xsl0000644000175000017500000000301012602773110017712 0ustar00smcvsmcv00000000000000 .html# dbus-1.10.6/doc/file-boilerplate.c0000644000175000017500000000174712602773110016676 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* FILENAME BRIEF FILE DESCRIPTION * * Copyright (C) YEAR COPYRIGHT HOLDER * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_FOO_H #define DBUS_FOO_H #endif /* DBUS_FOO_H */ dbus-1.10.6/doc/TODO0000644000175000017500000001341412602773110013775 0ustar00smcvsmcv00000000000000Important for 1.2 === - System bus activation - Windows port Important for 1.0 GLib Bindings === - Test point-to-point mode - Add support for getting sender - format_version in the object info doesn't look like it's handled correctly. The creator of the object info should specify some fixed number per struct version; the library should handle only specific numbers it knows about. There's no assumption that all numbers >= the given one are compatible. The idea is that new versions of the lib can offer totally different object info structs, but old versions keep working. Important for 1.0 Python bindings === - Hammer down API - Fix removing of signals from the match tree - Fix refcounting and userdata lifecycles - Write a generic mainloop Might as Well for 1.0 === - protocol version in each message is pretty silly Can Be Post 1.0 === - revamp dbus-launch a bit, see http://lists.freedesktop.org/archives/dbus/2006-October/005906.html for some thoughts. - clean up the creds issue on *BSD's in dbus/dbus-sysdeps-unix.c. They should work as is but we need to rearange it to make it clearer which method is being used. configure.in should be fixed up to make that decition. - _dbus_connection_unref_unlocked() is essentially always broken because the connection finalizer calls non-unlocked functions. One fix is to make the finalizer run with the lock held, but since it calls out to the app that may be pretty broken. More likely all the uses of unref_unlocked are just wrong. - if the GUID is obtained only during authentication, not in the address, we could still share the connection - Allow a dbus_g_proxy_to_string()/g_object_to_string() that would convert the proxy to an "IOR" and dbus_g_proxy_from_string() that would decode; using these, dbus-glib users could avoid DBusConnection entirely. Of course the same applies to other kinds of binding. This would use dbus_connection_open()'s connection-sharing feature to avoid massive proliferation of connections. - DBusWatchList/TimeoutList duplicate a lot of code, as do protected_change_watch/protected_change_timeout in dbus-connection.c and dbus-server.c. This could all be mopped up, cut-and-paste fixed, code size reduced. - change .service files to allow Names=list in addition to Name=string - The message bus internal code still says "service" for "name", "base service" for "unique name", "activate" for "start"; would be nice to clean up. - Property list feature on message bus (list of properties associated with a connection). May also include message matching rules that involve the properties of the source or destination connection. - Disconnecting the remote end on invalid UTF-8 is probably not a good idea. The definition of "valid" is slightly fuzzy. I think it might be better to just silently "fix" the UTF-8, or perhaps return an error. - build and install the Doxygen manual in Makefile when --enable-docs - if you send the same message to multiple connections, the serial number will only be right for one of them. Probably need to just write() the serial number, rather than putting it in the DBusMessage, or something. - perhaps the bus driver should have properties that reflect attributes of the session, such as hostname, architecture, operating system, etc. Could be useful for code that wants to special-case behavior for a particular host or class of hosts, for example. - currently the security policy stuff for messages to/from the bus driver is kind of strange; basically it's hardcoded that you can always talk to the driver, but the default config file has rules for it anyway, or something. it's conceptually screwy at the moment. - when making a method call, if the call serial were globally unique, we could forward the call serial along with any method calls made as a result of the first method call, and allow reentrancy that was strictly part of the call stack of said method call. But I don't really see how to do this without making the user pass around the call serial to all method calls all the time, or disallowing async calls. If done post 1.0 will probably be an optional/ugly-API type of thing. - I don't want to introduce DBusObject, but refcounting and object data could still be factored out into an internal "base class" perhaps. - Keep convenience wrappers in sync with bus methods - document the auth protocol as a set of states and transitions, and then reimplement it in those terms - recursive dispatch, see dbus_connection_dispatch() - do we need per-display activation; if so I'd like to do this by setting a "display ID" property on screen 0, with a GUID, and keying activation by said GUID. Otherwise you get all kinds of unrobust string/hostname-based mess. per-screen is then done by appending screen number to the display. If displays have a deterministic ID like this, you can do per-display by simply including GUID in the service name. - optimization and profiling! - Match rules aren't in the spec (probably a lot of methods on the bus are not) - the "break loader" and valid/invalid message tests are all disabled; they need to be fixed and re-enabled with the new message args stuff. I think I want to drop the .message files thing and just have code that generates messages, more like the tests for dbus-marshal-recursive.c (this is mostly done now, just needs some cleanup) - just before 1.0, try a HAVE_INT64=0 build and be sure it runs - Windows port needs recursive mutexes Should Be Post 1.0 === - look into supporting the concept of a "connection" generically (what does this TODO item mean?) - test/name-test should be named test/with-bus or something like that dbus-1.10.6/doc/dbus-uuidgen.1.xml.in0000644000175000017500000001105612602773110017166 0ustar00smcvsmcv00000000000000 dbus-uuidgen 1 User Commands D-Bus @DBUS_VERSION@ dbus-uuidgen Utility to generate UUIDs dbus-uuidgen --version --ensure =FILENAME --get =FILENAME DESCRIPTION The dbus-uuidgen command generates or reads a universally unique ID. Note that the D-Bus UUID has no relationship to RFC 4122 and does not generate UUIDs compatible with that spec. Many systems have a separate command for that (often called "uuidgen"). See http://www.freedesktop.org/software/dbus/ for more information about D-Bus. The primary usage of dbus-uuidgen is to run in the post-install script of a D-Bus package like this: dbus-uuidgen --ensure This will ensure that /var/lib/dbus/machine-id exists and has the uuid in it. It won't overwrite an existing uuid, since this id should remain fixed for a single machine until the next reboot at least. The important properties of the machine UUID are that 1) it remains unchanged until the next reboot and 2) it is different for any two running instances of the OS kernel. That is, if two processes see the same UUID, they should also see the same shared memory, UNIX domain sockets, local X displays, localhost.localdomain resolution, process IDs, and so forth. If you run dbus-uuidgen with no options it just prints a new uuid made up out of thin air. If you run it with --get, it prints the machine UUID by default, or the UUID in the specified file if you specify a file. If you try to change an existing machine-id on a running system, it will probably result in bad things happening. Don't try to change this file. Also, don't make it the same on two different systems; it needs to be different anytime there are two different kernels running. The UUID should be different on two different virtual machines, because there are two different kernels. OPTIONS The following options are supported: If a filename is not given, defaults to localstatedir/lib/dbus/machine-id (localstatedir is usually /var). If this file exists and is valid, the uuid in the file is printed on stdout. Otherwise, the command exits with a nonzero status. If a filename is not given, defaults to localstatedir/lib/dbus/machine-id (localstatedir is usually /var). If this file exists then it will be validated, and a failure code returned if it contains the wrong thing. If the file does not exist, it will be created with a new uuid in it. On success, prints no output. Print the version of dbus-uuidgen AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ dbus-1.10.6/doc/dbus-update-activation-environment.1.xml.in0000644000175000017500000002047012602773110023511 0ustar00smcvsmcv00000000000000 2015 Collabora Ltd. This man page is distributed under the same terms as dbus-update-activation-environment (MIT/X11). There is NO WARRANTY, to the extent permitted by law. dbus-update-activation-environment 1 User Commands D-Bus @DBUS_VERSION@ dbus-update-activation-environment update environment used for D-Bus session services dbus-update-activation-environment --systemd --verbose --all VAR VAR=VAL DESCRIPTION dbus-update-activation-environment updates the list of environment variables used by dbus-daemon --session when it activates session services without using systemd. With the option, if an instance of systemd --user is available on D-Bus, it also updates the list of environment variables used by systemd --user when it activates user services, including D-Bus session services for which dbus-daemon has been configured to delegate activation to systemd. This is very similar to the command provided by systemctl1). Variables that are special to dbus-daemon or systemd may be set, but their values will be overridden when a service is started. For instance, it is not useful to add DBUS_SESSION_BUS_ADDRESS to dbus-daemon's activation environment, although it might still be useful to add it to systemd's activation environment. OPTIONS Set all environment variables present in the environment used by dbus-update-activation-environment. Set environment variables for systemd user services as well as for traditional D-Bus session services. Output messages to standard error explaining what dbus-update-activation-environment is doing. VAR If VAR is present in the environment of dbus-update-activation-environment, set it to the same value for D-Bus services. Its value must be UTF-8 (if not, it is skipped with a warning). If VAR is not present in the environment, this argument is silently ignored. VAR=VAL Set VAR to VAL, which must be UTF-8. EXAMPLES dbus-update-activation-environment is primarily designed to be used in Linux distributions' X11 session startup scripts, in conjunction with the "user bus" design. To propagate DISPLAY and XAUTHORITY to dbus-daemon and, if present, systemd, and propagate DBUS_SESSION_BUS_ADDRESS to systemd: dbus-update-activation-environment --systemd \ DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY To propagate all environment variables except XDG_SEAT, XDG_SESSION_ID and XDG_VTNR to dbus-daemon (and, if present, systemd) for compatibility with legacy X11 session startup scripts: # in a subshell so the variables remain set in the # parent script ( unset XDG_SEAT unset XDG_SESSION_ID unset XDG_VTNR dbus-update-activation-environment --systemd --all ) EXIT STATUS dbus-update-activation-environment exits with status 0 on success, EX_USAGE (64) on invalid command-line options, EX_OSERR (71) if unable to connect to the session bus, or EX_UNAVAILABLE (69) if unable to set the environment variables. Other nonzero exit codes might be added in future versions. ENVIRONMENT DBUS_SESSION_BUS_ADDRESS, XDG_RUNTIME_DIR and/or DISPLAY are used to find the address of the session bus. LIMITATIONS dbus-daemon does not provide a way to unset environment variables after they have been set (although systemd does), so dbus-update-activation-environment does not offer this functionality either. POSIX does not specify the encoding of non-ASCII environment variable names or values and allows them to contain any non-zero byte, but neither dbus-daemon nor systemd supports environment variables with non-UTF-8 names or values. Accordingly, dbus-update-activation-environment assumes that any name or value that appears to be valid UTF-8 is intended to be UTF-8, and ignores other names or values with a warning. BUGS Please send bug reports to the D-Bus bug tracker or mailing list. See http://www.freedesktop.org/software/dbus/. SEE ALSO dbus-daemon1, systemd1, the command of systemctl1 dbus-1.10.6/doc/dbus-test-tool.1.xml.in0000644000175000017500000002720412602773110017462 0ustar00smcvsmcv00000000000000 2015 Collabora Ltd. This man page is distributed under the same terms as dbus-test-tool (GPL-2+). There is NO WARRANTY, to the extent permitted by law. dbus-test-tool 1 User Commands D-Bus @DBUS_VERSION@ dbus-test-tool D-Bus traffic generator and test tool dbus-test-tool black-hole --session --system --name=NAME --no-read dbus-test-tool echo --session --system --name=NAME --sleep=MS dbus-test-tool spam --session --system --dest=NAME --count=N --flood --ignore-errors --messages-per-conn=N --no-reply --queue=N --seed=SEED --string --bytes --empty --payload=S --stdin --message-stdin --random-size DESCRIPTION dbus-test-tool is a multi-purpose tool for debugging and profiling D-Bus. dbus-test-tool black-hole connects to D-Bus, optionally requests a name, then does not reply to messages. It normally reads and discards messages from its D-Bus socket, but can be configured to sleep forever without reading. dbus-test-tool echo connects to D-Bus, optionally requests a name, then sends back an empty reply to every method call, after an optional delay. dbus-test-tool spam connects to D-Bus and makes repeated method calls, normally named com.example.Spam. OPTIONS Common options Connect to the session bus. This is the default. Connect to the system bus. black-hole mode NAME Before proceeding, request ownership of the well-known bus name NAME, for example com.example.NoReply. By default, no name is requested, and the tool can only be addressed by a unique bus name such as :1.23. Do not read from the D-Bus socket. echo mode NAME Before proceeding, request ownership of the well-known bus name NAME, for example com.example.Echo. By default, no name is requested, and the tool can only be addressed by a unique bus name such as :1.23. MS Block for MS milliseconds before replying to a method call. spam mode NAME Send method calls to the well-known or unique bus name NAME. The default is the dbus-daemon, org.freedesktop.DBus. N Send N method calls in total. The default is 1. N Send N method calls before waiting for any replies, then send one new call per reply received, keeping N method calls "in flight" at all times until the number of messages specified with the option have been sent. The default is 1, unless is used. Send all messages without waiting for a reply, equivalent to with an arbitrarily large N. Set the "no reply desired" flag on the messages. This implies , since it disables the replies that would be used for a finite length. N If given, send N method calls on the same connection, then disconnect and reconnect. The default is to use the same connection for all method calls. The payload of each message is a UTF-8 string. This is the default. The actual string used is given by the or option, defaulting to "hello, world!". The payload of each message is a byte-array. The actual bytes used are given by the or option, defaulting to the ASCII encoding of "hello, world!". The messages have no payload. S Use S as the or in the messages. The default is "hello, world!". Read from standard input until end-of-file is reached, and use that as the or in the messages. Read a complete binary D-Bus method call message from standard input, and use that for each method call. Read whitespace-separated ASCII decimal numbers from standard input, choose one at random for each message, and send a message whose payload is a string of that length. SEED Use SEED as the seed for the pseudorandom number generator, to have somewhat repeatable sequences of random messages. BUGS Please send bug reports to the D-Bus bug tracker or mailing list. See http://www.freedesktop.org/software/dbus/. SEE ALSO dbus-send1 dbus-1.10.6/doc/dbus-send.1.xml.in0000644000175000017500000001551612602773110016464 0ustar00smcvsmcv00000000000000 dbus-send 1 User Commands D-Bus @DBUS_VERSION@ dbus-send Send a message to a message bus dbus-send --system --session --address=ADDRESS --dest=NAME --print-reply =literal --reply-timeout=MSEC --type=TYPE OBJECT_PATH INTERFACE.MEMBER CONTENTS DESCRIPTION The dbus-send command is used to send a message to a D-Bus message bus. See http://www.freedesktop.org/software/dbus/ for more information about the big picture. There are two well-known message buses: the systemwide message bus (installed on many systems as the "messagebus" service) and the per-user-login-session message bus (started each time a user logs in). The and options direct dbus-send to send messages to the system or session buses respectively. If neither is specified, dbus-send sends to the session bus. Nearly all uses of dbus-send must provide the argument which is the name of a connection on the bus to send the message to. If is omitted, no destination is set. The object path and the name of the message to send must always be specified. Following arguments, if any, are the message contents (message arguments). These are given as type-specified values and may include containers (arrays, dicts, and variants) as described below. <contents> ::= <item> | <container> [ <item> | <container>...] <item> ::= <type>:<value> <container> ::= <array> | <dict> | <variant> <array> ::= array:<type>:<value>[,<value>...] <dict> ::= dict:<type>:<type>:<key>,<value>[,<key>,<value>...] <variant> ::= variant:<type>:<value> <type> ::= string | int16 | uint 16 | int32 | uint32 | int64 | uint64 | double | byte | boolean | objpath D-Bus supports more types than these, but dbus-send currently does not. Also, dbus-send does not permit empty containers or nested containers (e.g. arrays of variants). Here is an example invocation: dbus-send --dest=org.freedesktop.ExampleName \ /org/freedesktop/sample/object/name \ org.freedesktop.ExampleInterface.ExampleMethod \ int32:47 string:'hello world' double:65.32 \ array:string:"1st item","next item","last item" \ dict:string:int32:"one",1,"two",2,"three",3 \ variant:int32:-8 \ objpath:/org/freedesktop/sample/object/name Note that the interface is separated from a method or signal name by a dot, though in the actual protocol the interface and the interface member are separate fields. OPTIONS The following options are supported: NAME Specify the name of the connection to receive the message. Block for a reply to the message sent, and print any reply received in a human-readable form. It also means the message type () is method_call. Block for a reply to the message sent, and print the body of the reply. If the reply is an object path or a string, it is printed literally, with no punctuation, escape characters etc. MSEC Wait for a reply for up to MSEC milliseconds. The default is implementation‐defined, typically 25 seconds. Send to the system message bus. Send to the session message bus. (This is the default.) ADDRESS Send to ADDRESS. TYPE Specify method_call or signal (defaults to "signal"). AUTHOR dbus-send was written by Philip Blundell. BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ dbus-1.10.6/doc/dbus-run-session.1.xml.in0000644000175000017500000001362212602773110020014 0ustar00smcvsmcv00000000000000 dbus-run-session 1 User Commands D-Bus @DBUS_VERSION@ dbus-run-session start a process as a new D-Bus session dbus-run-session --config-file FILENAME --dbus-daemon BINARY -- PROGRAM ARGUMENTS dbus-run-session --help dbus-run-session --version DESCRIPTION dbus-run-session is used to start a session bus instance of dbus-daemon from a shell script, and start a specified program in that session. The dbus-daemon will run for as long as the program does, after which it will terminate. One use is to run a shell with its own dbus-daemon in a text‐mode or SSH session, and have the dbus-daemon terminate automatically on leaving the sub‐shell, like this: dbus-run-session -- bash or to replace the login shell altogether, by combining dbus-run-session with the exec builtin: exec dbus-run-session -- bash Another use is to run regression tests and similar things in an isolated D-Bus session, to avoid either interfering with the "real" D-Bus session or relying on there already being a D-Bus session active, for instance: dbus-run-session -- make check or (in automake1): AM_TESTS_ENVIRONMENT = export MY_DEBUG=all; LOG_COMPILER = dbus-run-session AM_LOG_FLAGS = -- OPTIONS FILENAME, FILENAME Pass FILENAME to the bus daemon, instead of passing it the argument. See dbus-daemon1. BINARY, BINARY Run BINARY as dbus-daemon1, instead of searching the PATH in the usual way for an executable called dbus-daemon. Print usage information and exit. Print the version of dbus-run-session and exit. EXIT STATUS dbus-run-session exits with the exit status of PROGRAM, 0 if the or options were used, 127 on an error within dbus-run-session itself, or 128+n if the PROGRAM was killed by signal n. ENVIRONMENT PATH is searched to find PROGRAM, and (if the --dbus-daemon option is not used or its argument does not contain a / character) to find dbus-daemon. The session bus' address is made available to PROGRAM in the environment variable DBUS_SESSION_BUS_ADDRESS. The variables DBUS_SESSION_BUS_PID, DBUS_SESSION_BUS_WINDOWID, DBUS_STARTER_BUS_TYPE and DBUS_STARTER_ADDRESS are removed from the environment, if present. BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ SEE ALSO dbus-daemon1, dbus-launch1 dbus-1.10.6/doc/dbus-monitor.1.xml.in0000644000175000017500000001177512602773110017225 0ustar00smcvsmcv00000000000000 dbus-monitor 1 User Commands D-Bus @DBUS_VERSION@ dbus-monitor debug probe to print message bus messages dbus-monitor --system --session --address ADDRESS --profile --monitor --pcap --binary watchexpressions DESCRIPTION The dbus-monitor command is used to monitor messages going through a D-Bus message bus. See http://www.freedesktop.org/software/dbus/ for more information about the big picture. There are two well-known message buses: the systemwide message bus (installed on many systems as the "messagebus" service) and the per-user-login-session message bus (started each time a user logs in). The --system and --session options direct dbus-monitor to monitor the system or session buses respectively. If neither is specified, dbus-monitor monitors the session bus. dbus-monitor has two different text output modes: the 'classic'-style monitoring mode, and profiling mode. The profiling format is a compact format with a single line per message and microsecond-resolution timing information. The --profile and --monitor options select the profiling and monitoring output format respectively. dbus-monitor also has two binary output modes. The binary mode, selected by --binary, outputs the entire binary message stream (without the initial authentication handshake). The PCAP mode, selected by --pcap, adds a PCAP file header to the beginning of the output, and prepends a PCAP message header to each message; this produces a binary file that can be read by, for instance, Wireshark. If no mode is specified, dbus-monitor uses the monitoring output format. In order to get dbus-monitor to see the messages you are interested in, you should specify a set of watch expressions as you would expect to be passed to the dbus_bus_add_match function. The message bus configuration may keep dbus-monitor from seeing all messages, especially if you run the monitor as a non-root user. OPTIONS Monitor the system message bus. Monitor the session message bus. (This is the default.) Monitor an arbitrary message bus given at ADDRESS. Use the profiling output format. Use the monitoring output format. (This is the default.) EXAMPLE Here is an example of using dbus-monitor to watch for the gnome typing monitor to say things dbus-monitor "type='signal',sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'" AUTHOR dbus-monitor was written by Philip Blundell. The profiling output mode was added by Olli Salli. BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ dbus-1.10.6/doc/dbus-launch.1.xml.in0000644000175000017500000002607112602773110017003 0ustar00smcvsmcv00000000000000 dbus-launch 1 User Commands D-Bus @DBUS_VERSION@ dbus-launch Utility to start a message bus from a shell script dbus-launch --version --help --sh-syntax --csh-syntax --auto-syntax --binary-syntax --close-stderr --exit-with-session --autolaunch=MACHINEID --config-file=FILENAME PROGRAM ARGS DESCRIPTION The dbus-launch command is used to start a session bus instance of dbus-daemon from a shell script. It would normally be called from a user's login scripts. Unlike the daemon itself, dbus-launch exits, so backticks or the $() construct can be used to read information from dbus-launch. With no arguments, dbus-launch will launch a session bus instance and print the address and PID of that instance to standard output. You may specify a program to be run; in this case, dbus-launch will launch a session bus instance, set the appropriate environment variables so the specified program can find the bus, and then execute the specified program, with the specified arguments. See below for examples. If you launch a program, dbus-launch will not print the information about the new bus to standard output. When dbus-launch prints bus information to standard output, by default it is in a simple key-value pairs format. However, you may request several alternate syntaxes using the --sh-syntax, --csh-syntax, --binary-syntax, or --auto-syntax options. Several of these cause dbus-launch to emit shell code to set up the environment. With the --auto-syntax option, dbus-launch looks at the value of the SHELL environment variable to determine which shell syntax should be used. If SHELL ends in "csh", then csh-compatible code is emitted; otherwise Bourne shell code is emitted. Instead of passing --auto-syntax, you may explicitly specify a particular one by using --sh-syntax for Bourne syntax, or --csh-syntax for csh syntax. In scripts, it's more robust to avoid --auto-syntax and you hopefully know which shell your script is written in. See http://www.freedesktop.org/software/dbus/ for more information about D-Bus. See also the man page for dbus-daemon. EXAMPLES Distributions running dbus-launch as part of a standard X session should run dbus-launch --exit-with-session after the X server has started and become available, as a wrapper around the "main" X client (typically a session manager or window manager), as in these examples:
    dbus-launch --exit-with-session gnome-session dbus-launch --exit-with-session openbox dbus-launch --exit-with-session ~/.xsession
    If your distribution does not do this, you can achieve similar results by running your session or window manager in the same way in a script run by your X session, such as ~/.xsession, ~/.xinitrc or ~/.Xclients. To start a D-Bus session within a text-mode session, do not use dbus-launch. Instead, see dbus-run-session1. ## test for an existing bus daemon, just to be safe if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then ## if not found, launch a new one eval `dbus-launch --sh-syntax` echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS" fi Note that in this case, dbus-launch will exit, and dbus-daemon will not be terminated automatically on logout.
    AUTOMATIC LAUNCHING If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use D-Bus, by default the process will attempt to invoke dbus-launch with the --autolaunch option to start up a new session bus or find the existing bus address on the X display or in a file in ~/.dbus/session-bus/ Whenever an autolaunch occurs, the application that had to start a new bus will be in its own little world; it can effectively end up starting a whole new session if it tries to use a lot of bus services. This can be suboptimal or even totally broken, depending on the app and what it tries to do. There are two common reasons for autolaunch. One is ssh to a remote machine. The ideal fix for that would be forwarding of DBUS_SESSION_BUS_ADDRESS in the same way that DISPLAY is forwarded. In the meantime, you can edit the session.conf config file to have your session bus listen on TCP, and manually set DBUS_SESSION_BUS_ADDRESS, if you like. The second common reason for autolaunch is an su to another user, and display of X applications running as the second user on the display belonging to the first user. Perhaps the ideal fix in this case would be to allow the second user to connect to the session bus of the first user, just as they can connect to the first user's display. However, a mechanism for that has not been coded. You can always avoid autolaunch by manually setting DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default address if none is set is "autolaunch:", so if any other address is set there will be no autolaunch. You can however include autolaunch in an explicit session bus address as a fallback, for example DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" - in that case if the first address doesn't work, processes will autolaunch. (The bus address variable contains a comma-separated list of addresses to try.) The --autolaunch option is considered an internal implementation detail of libdbus, and in fact there are plans to change it. There's no real reason to use it outside of the libdbus implementation anyhow. OPTIONS The following options are supported: Choose --csh-syntax or --sh-syntax based on the SHELL environment variable. Write to stdout a nul-terminated bus address, then the bus PID as a binary integer of size sizeof(pid_t), then the bus X window ID as a binary integer of size sizeof(long). Integers are in the machine's byte order, not network byte order or any other canonical byte order. Close the standard error output stream before starting the D-Bus daemon. This is useful if you want to capture dbus-launch error messages but you don't want dbus-daemon to keep the stream open to your application. Pass --config-file=FILENAME to the bus daemon, instead of passing it the --session argument. See the man page for dbus-daemon Emit csh compatible code to set up environment variables. If this option is provided, a persistent "babysitter" process will be created that watches stdin for HUP and tries to connect to the X server. If this process gets a HUP on stdin or loses its X connection, it kills the message bus daemon. This option implies that dbus-launch should scan for a previously-started session and reuse the values found there. If no session is found, it will start a new session. The --exit-with-session option is implied if --autolaunch is given. This option is for the exclusive use of libdbus, you do not want to use it manually. It may change in the future. Emit Bourne-shell compatible code to set up environment variables. Print the version of dbus-launch Print the help info of dbus-launch NOTES If you run dbus-launch myapp (with any other options), dbus-daemon will not exit when myapp terminates: this is because myapp is assumed to be part of a larger session, rather than a session in its own right. AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/
    dbus-1.10.6/doc/dbus-daemon.1.xml.in0000644000175000017500000011436612602773110017001 0ustar00smcvsmcv00000000000000 dbus-daemon 1 User Commands D-Bus @DBUS_VERSION@ dbus-daemon Message bus daemon dbus-daemon dbus-daemon --version --session --system --config-file=FILE --print-address =DESCRIPTOR --print-pid =DESCRIPTOR --fork DESCRIPTION dbus-daemon is the D-Bus message bus daemon. See http://www.freedesktop.org/software/dbus/ for more information about the big picture. D-Bus is first a library that provides one-to-one communication between any two applications; dbus-daemon is an application that uses this library to implement a message bus daemon. Multiple programs connect to the message bus daemon and can exchange messages with one another. There are two standard message bus instances: the systemwide message bus (installed on many systems as the "messagebus" init service) and the per-user-login-session message bus (started each time a user logs in). dbus-daemon is used for both of these instances, but with a different configuration file. The --session option is equivalent to "--config-file=@EXPANDED_DATADIR@/dbus-1/session.conf" and the --system option is equivalent to "--config-file=@EXPANDED_DATADIR@/dbus-1/system.conf". By creating additional configuration files and using the --config-file option, additional special-purpose message bus daemons could be created. The systemwide daemon is normally launched by an init script, standardly called simply "messagebus". The systemwide daemon is largely used for broadcasting system events, such as changes to the printer queue, or adding/removing devices. The per-session daemon is used for various interprocess communication among desktop applications (however, it is not tied to X or the GUI in any way). SIGHUP will cause the D-Bus daemon to PARTIALLY reload its configuration file and to flush its user/group information caches. Some configuration changes would require kicking all apps off the bus; so they will only take effect if you restart the daemon. Policy changes should take effect with SIGHUP. OPTIONS The following options are supported: Use the given configuration file. Force the message bus to fork and become a daemon, even if the configuration file does not specify that it should. In most contexts the configuration file already gets this right, though. This option is not supported on Windows. Force the message bus not to fork and become a daemon, even if the configuration file specifies that it should. On Windows, the dbus-daemon never forks, so this option is allowed but does nothing. Print the address of the message bus to standard output, or to the given file descriptor. This is used by programs that launch the message bus. Print the process ID of the message bus to standard output, or to the given file descriptor. This is used by programs that launch the message bus. Use the standard configuration file for the per-login-session message bus. Use the standard configuration file for the systemwide message bus. Print the version of the daemon. Print the introspection information for all D-Bus internal interfaces. Set the address to listen on. This option overrides the address configured in the configuration file. Enable systemd-style service activation. Only useful in conjunction with the systemd system and session manager on Linux. Don't write a PID file even if one is configured in the configuration files. CONFIGURATION FILE A message bus daemon has a configuration file that specializes it for a particular application. For example, one configuration file might set up the message bus to be a systemwide message bus, while another might set it up to be a per-user-login-session bus. The configuration file also establishes resource limits, security parameters, and so forth. The configuration file is not part of any interoperability specification and its backward compatibility is not guaranteed; this document is documentation, not specification. The standard systemwide and per-session message bus setups are configured in the files "@EXPANDED_DATADIR@/dbus-1/system.conf" and "@EXPANDED_DATADIR@/dbus-1/session.conf". These files normally <include> a system-local.conf or session-local.conf in @EXPANDED_SYSCONFDIR@/dbus-1; you can put local overrides in those files to avoid modifying the primary configuration files. The configuration file is an XML document. It must have the following doctype declaration: <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> The following elements may be present in the configuration file. <busconfig> Root element. <type> The well-known type of the message bus. Currently known values are "system" and "session"; if other values are set, they should be either added to the D-Bus specification, or namespaced. The last <type> element "wins" (previous values are ignored). This element only controls which message bus specific environment variables are set in activated clients. Most of the policy that distinguishes a session bus from the system bus is controlled from the other elements in the configuration file. If the well-known type of the message bus is "session", then the DBUS_STARTER_BUS_TYPE environment variable will be set to "session" and the DBUS_SESSION_BUS_ADDRESS environment variable will be set to the address of the session bus. Likewise, if the type of the message bus is "system", then the DBUS_STARTER_BUS_TYPE environment variable will be set to "system" and the DBUS_SESSION_BUS_ADDRESS environment variable will be set to the address of the system bus (which is normally well known anyway). Example: <type>session</type> <include> Include a file <include>filename.conf</include> at this point. If the filename is relative, it is located relative to the configuration file doing the including. <include> has an optional attribute "ignore_missing=(yes|no)" which defaults to "no" if not provided. This attribute controls whether it's a fatal error for the included file to be absent. <includedir> Include all files in <includedir>foo.d</includedir> at this point. Files in the directory are included in undefined order. Only files ending in ".conf" are included. This is intended to allow extension of the system bus by particular packages. For example, if CUPS wants to be able to send out notification of printer queue changes, it could install a file to @EXPANDED_DATADIR@/dbus-1/system.d or @EXPANDED_SYSCONFDIR@/dbus-1/system.d that allowed all apps to receive this message and allowed the printer daemon user to send it. <user> The user account the daemon should run as, as either a username or a UID. If the daemon cannot change to this UID on startup, it will exit. If this element is not present, the daemon will not change or care about its UID. The last <user> entry in the file "wins", the others are ignored. The user is changed after the bus has completed initialization. So sockets etc. will be created before changing user, but no data will be read from clients before changing user. This means that sockets and PID files can be created in a location that requires root privileges for writing. <fork> If present, the bus daemon becomes a real daemon (forks into the background, etc.). This is generally used rather than the --fork command line option. <keep_umask> If present, the bus daemon keeps its original umask when forking. This may be useful to avoid affecting the behavior of child processes. <syslog> If present, the bus daemon will log to syslog. <pidfile> If present, the bus daemon will write its pid to the specified file. The --nopidfile command-line option takes precedence over this setting. <allow_anonymous> If present, connections that authenticated using the ANONYMOUS mechanism will be authorized to connect. This option has no practical effect unless the ANONYMOUS mechanism has also been enabled using the <auth> element, described below. <listen> Add an address that the bus should listen on. The address is in the standard D-Bus format that contains a transport name plus possible parameters/options. Example: <listen>unix:path=/tmp/foo</listen> Example: <listen>tcp:host=localhost,port=1234</listen> If there are multiple <listen> elements, then the bus listens on multiple addresses. The bus will pass its address to started services or other interested parties with the last address given in <listen> first. That is, apps will try to connect to the last <listen> address first. tcp sockets can accept IPv4 addresses, IPv6 addresses or hostnames. If a hostname resolves to multiple addresses, the server will bind to all of them. The family=ipv4 or family=ipv6 options can be used to force it to bind to a subset of addresses Example: <listen>tcp:host=localhost,port=0,family=ipv4</listen> A special case is using a port number of zero (or omitting the port), which means to choose an available port selected by the operating system. The port number chosen can be obtained with the --print-address command line parameter and will be present in other cases where the server reports its own address, such as when DBUS_SESSION_BUS_ADDRESS is set. Example: <listen>tcp:host=localhost,port=0</listen> tcp/nonce-tcp addresses also allow a bind=hostname option, used in a listenable address to configure the interface on which the server will listen: either the hostname is the IP address of one of the local machine's interfaces (most commonly 127.0.0.1), a DNS name that resolves to one of those IP addresses, '0.0.0.0' to listen on all IPv4 interfaces simultaneously, or '::' to listen on all IPv4 and IPv6 interfaces simultaneously (if supported by the OS). If not specified, the default is the same value as "host". Example: <listen>tcp:host=localhost,bind=0.0.0.0,port=0</listen> <auth> Lists permitted authorization mechanisms. If this element doesn't exist, then all known mechanisms are allowed. If there are multiple <auth> elements, all the listed mechanisms are allowed. The order in which mechanisms are listed is not meaningful. Example: <auth>EXTERNAL</auth> Example: <auth>DBUS_COOKIE_SHA1</auth> <servicedir> Adds a directory to scan for .service files. Directories are scanned starting with the first to appear in the config file (the first .service file found that provides a particular service will be used). Service files tell the bus how to automatically start a program. They are primarily used with the per-user-session bus, not the systemwide bus. <standard_session_servicedirs/> <standard_session_servicedirs/> is equivalent to specifying a series of <servicedir/> elements for each of the data directories in the "XDG Base Directory Specification" with the subdirectory "dbus-1/services", so for example "/usr/share/dbus-1/services" would be among the directories searched. The "XDG Base Directory Specification" can be found at http://freedesktop.org/wiki/Standards/basedir-spec if it hasn't moved, otherwise try your favorite search engine. The <standard_session_servicedirs/> option is only relevant to the per-user-session bus daemon defined in @EXPANDED_SYSCONFDIR@/dbus-1/session.conf. Putting it in any other configuration file would probably be nonsense. <standard_system_servicedirs/> <standard_system_servicedirs/> specifies the standard system-wide activation directories that should be searched for service files. This option defaults to @EXPANDED_DATADIR@/dbus-1/system-services. The <standard_system_servicedirs/> option is only relevant to the per-system bus daemon defined in @EXPANDED_DATADIR@/dbus-1/system.conf. Putting it in any other configuration file would probably be nonsense. <servicehelper/> <servicehelper/> specifies the setuid helper that is used to launch system daemons with an alternate user. Typically this should be the dbus-daemon-launch-helper executable in located in libexec. The <servicehelper/> option is only relevant to the per-system bus daemon defined in @EXPANDED_DATADIR@/dbus-1/system.conf. Putting it in any other configuration file would probably be nonsense. <limit> <limit> establishes a resource limit. For example: <limit name="max_message_size">64</limit> <limit name="max_completed_connections">512</limit> The name attribute is mandatory. Available limit names are: "max_incoming_bytes" : total size in bytes of messages incoming from a single connection "max_incoming_unix_fds" : total number of unix fds of messages incoming from a single connection "max_outgoing_bytes" : total size in bytes of messages queued up for a single connection "max_outgoing_unix_fds" : total number of unix fds of messages queued up for a single connection "max_message_size" : max size of a single message in bytes "max_message_unix_fds" : max unix fds of a single message "service_start_timeout" : milliseconds (thousandths) until a started service has to connect "auth_timeout" : milliseconds (thousandths) a connection is given to authenticate "pending_fd_timeout" : milliseconds (thousandths) a fd is given to be transmitted to dbus-daemon before disconnecting the connection "max_completed_connections" : max number of authenticated connections "max_incomplete_connections" : max number of unauthenticated connections "max_connections_per_user" : max number of completed connections from the same user "max_pending_service_starts" : max number of service launches in progress at the same time "max_names_per_connection" : max number of names a single connection can own "max_match_rules_per_connection": max number of match rules for a single connection "max_replies_per_connection" : max number of pending method replies per connection (number of calls-in-progress) "reply_timeout" : milliseconds (thousandths) until a method call times out The max incoming/outgoing queue sizes allow a new message to be queued if one byte remains below the max. So you can in fact exceed the max by max_message_size. max_completed_connections divided by max_connections_per_user is the number of users that can work together to denial-of-service all other users by using up all connections on the systemwide bus. Limits are normally only of interest on the systemwide bus, not the user session buses. <policy> The <policy> element defines a security policy to be applied to a particular set of connections to the bus. A policy is made up of <allow> and <deny> elements. Policies are normally used with the systemwide bus; they are analogous to a firewall in that they allow expected traffic and prevent unexpected traffic. Currently, the system bus has a default-deny policy for sending method calls and owning bus names. Everything else, in particular reply messages, receive checks, and signals has a default allow policy. In general, it is best to keep system services as small, targeted programs which run in their own process and provide a single bus name. Then, all that is needed is an <allow> rule for the "own" permission to let the process claim the bus name, and a "send_destination" rule to allow traffic from some or all uids to your service. The <policy> element has one of four attributes: context="(default|mandatory)" at_console="(true|false)" user="username or userid" group="group name or gid" Policies are applied to a connection as follows: - all context="default" policies are applied - all group="connection's user's group" policies are applied in undefined order - all user="connection's auth user" policies are applied in undefined order - all at_console="true" policies are applied - all at_console="false" policies are applied - all context="mandatory" policies are applied Policies applied later will override those applied earlier, when the policies overlap. Multiple policies with the same user/group/context are applied in the order they appear in the config file. <deny> <allow> A <deny> element appears below a <policy> element and prohibits some action. The <allow> element makes an exception to previous <deny> statements, and works just like <deny> but with the inverse meaning. The possible attributes of these elements are: send_interface="interface_name" send_member="method_or_signal_name" send_error="error_name" send_destination="name" send_type="method_call" | "method_return" | "signal" | "error" send_path="/path/name" receive_interface="interface_name" receive_member="method_or_signal_name" receive_error="error_name" receive_sender="name" receive_type="method_call" | "method_return" | "signal" | "error" receive_path="/path/name" send_requested_reply="true" | "false" receive_requested_reply="true" | "false" eavesdrop="true" | "false" own="name" own_prefix="name" user="username" group="groupname" Examples: <deny send_destination="org.freedesktop.Service" send_interface="org.freedesktop.System" send_member="Reboot"/> <deny send_destination="org.freedesktop.System"/> <deny receive_sender="org.freedesktop.System"/> <deny user="john"/> <deny group="enemies"/> The <deny> element's attributes determine whether the deny "matches" a particular action. If it matches, the action is denied (unless later rules in the config file allow it). send_destination and receive_sender rules mean that messages may not be sent to or received from the *owner* of the given name, not that they may not be sent *to that name*. That is, if a connection owns services A, B, C, and sending to A is denied, sending to B or C will not work either. The other send_* and receive_* attributes are purely textual/by-value matches against the given field in the message header. "Eavesdropping" occurs when an application receives a message that was explicitly addressed to a name the application does not own, or is a reply to such a message. Eavesdropping thus only applies to messages that are addressed to services and replies to such messages (i.e. it does not apply to signals). For <allow>, eavesdrop="true" indicates that the rule matches even when eavesdropping. eavesdrop="false" is the default and means that the rule only allows messages to go to their specified recipient. For <deny>, eavesdrop="true" indicates that the rule matches only when eavesdropping. eavesdrop="false" is the default for <deny> also, but here it means that the rule applies always, even when not eavesdropping. The eavesdrop attribute can only be combined with send and receive rules (with send_* and receive_* attributes). The [send|receive]_requested_reply attribute works similarly to the eavesdrop attribute. It controls whether the <deny> or <allow> matches a reply that is expected (corresponds to a previous method call message). This attribute only makes sense for reply messages (errors and method returns), and is ignored for other message types. For <allow>, [send|receive]_requested_reply="true" is the default and indicates that only requested replies are allowed by the rule. [send|receive]_requested_reply="false" means that the rule allows any reply even if unexpected. For <deny>, [send|receive]_requested_reply="false" is the default but indicates that the rule matches only when the reply was not requested. [send|receive]_requested_reply="true" indicates that the rule applies always, regardless of pending reply state. user and group denials mean that the given user or group may not connect to the message bus. For "name", "username", "groupname", etc. the character "*" can be substituted, meaning "any." Complex globs like "foo.bar.*" aren't allowed for now because they'd be work to implement and maybe encourage sloppy security anyway. <allow own_prefix="a.b"/> allows you to own the name "a.b" or any name whose first dot-separated elements are "a.b": in particular, you can own "a.b.c" or "a.b.c.d", but not "a.bc" or "a.c". This is useful when services like Telepathy and ReserveDevice define a meaning for subtrees of well-known names, such as org.freedesktop.Telepathy.ConnectionManager.(anything) and org.freedesktop.ReserveDevice1.(anything). It does not make sense to deny a user or group inside a <policy> for a user or group; user/group denials can only be inside context="default" or context="mandatory" policies. A single <deny> rule may specify combinations of attributes such as send_destination and send_interface and send_type. In this case, the denial applies only if both attributes match the message being denied. e.g. <deny send_interface="foo.bar" send_destination="foo.blah"/> would deny messages with the given interface AND the given bus name. To get an OR effect you specify multiple <deny> rules. You can't include both send_ and receive_ attributes on the same rule, since "whether the message can be sent" and "whether it can be received" are evaluated separately. Be careful with send_interface/receive_interface, because the interface field in messages is optional. In particular, do NOT specify <deny send_interface="org.foo.Bar"/>! This will cause no-interface messages to be blocked for all services, which is almost certainly not what you intended. Always use rules of the form: <deny send_interface="org.foo.Bar" send_destination="org.foo.Service"/> <selinux> The <selinux> element contains settings related to Security Enhanced Linux. More details below. <associate> An <associate> element appears below an <selinux> element and creates a mapping. Right now only one kind of association is possible: <associate own="org.freedesktop.Foobar" context="foo_t"/> This means that if a connection asks to own the name "org.freedesktop.Foobar" then the source context will be the context of the connection and the target context will be "foo_t" - see the short discussion of SELinux below. Note, the context here is the target context when requesting a name, NOT the context of the connection owning the name. There's currently no way to set a default for owning any name, if we add this syntax it will look like: <associate own="*" context="foo_t"/> If you find a reason this is useful, let the developers know. Right now the default will be the security context of the bus itself. If two <associate> elements specify the same name, the element appearing later in the configuration file will be used. <apparmor> The <apparmor> element is used to configure AppArmor mediation on the bus. It can contain one attribute that specifies the mediation mode: <apparmor mode="(enabled|disabled|required)"/> The default mode is "enabled". In "enabled" mode, AppArmor mediation will be performed if AppArmor support is available in the kernel. If it is not available, dbus-daemon will start but AppArmor mediation will not occur. In "disabled" mode, AppArmor mediation is disabled. In "required" mode, AppArmor mediation will be enabled if AppArmor support is available, otherwise dbus-daemon will refuse to start. The AppArmor mediation mode of the bus cannot be changed after the bus starts. Modifying the mode in the configuration file and sending a SIGHUP signal to the daemon has no effect on the mediation mode. SELinux See http://www.nsa.gov/selinux/ for full details on SELinux. Some useful excerpts: Every subject (process) and object (e.g. file, socket, IPC object, etc) in the system is assigned a collection of security attributes, known as a security context. A security context contains all of the security attributes associated with a particular subject or object that are relevant to the security policy. In order to better encapsulate security contexts and to provide greater efficiency, the policy enforcement code of SELinux typically handles security identifiers (SIDs) rather than security contexts. A SID is an integer that is mapped by the security server to a security context at runtime. When a security decision is required, the policy enforcement code passes a pair of SIDs (typically the SID of a subject and the SID of an object, but sometimes a pair of subject SIDs or a pair of object SIDs), and an object security class to the security server. The object security class indicates the kind of object, e.g. a process, a regular file, a directory, a TCP socket, etc. Access decisions specify whether or not a permission is granted for a given pair of SIDs and class. Each object class has a set of associated permissions defined to control operations on objects with that class. D-Bus performs SELinux security checks in two places. First, any time a message is routed from one connection to another connection, the bus daemon will check permissions with the security context of the first connection as source, security context of the second connection as target, object class "dbus" and requested permission "send_msg". If a security context is not available for a connection (impossible when using UNIX domain sockets), then the target context used is the context of the bus daemon itself. There is currently no way to change this default, because we're assuming that only UNIX domain sockets will be used to connect to the systemwide bus. If this changes, we'll probably add a way to set the default connection context. Second, any time a connection asks to own a name, the bus daemon will check permissions with the security context of the connection as source, the security context specified for the name in the config file as target, object class "dbus" and requested permission "acquire_svc". The security context for a bus name is specified with the <associate> element described earlier in this document. If a name has no security context associated in the configuration file, the security context of the bus daemon itself will be used. AppArmor The AppArmor confinement context is stored when applications connect to the bus. The confinement context consists of a label and a confinement mode. When a security decision is required, the daemon uses the confinement context to query the AppArmor policy to determine if the action should be allowed or denied and if the action should be audited. The daemon performs AppArmor security checks in three places. First, any time a message is routed from one connection to another connection, the bus daemon will check permissions with the label of the first connection as source, label and/or connection name of the second connection as target, along with the bus name, the path name, the interface name, and the member name. Reply messages, such as method_return and error messages, are implicitly allowed if they are in response to a message that has already been allowed. Second, any time a connection asks to own a name, the bus daemon will check permissions with the label of the connection as source, the requested name as target, along with the bus name. Third, any time a connection attempts to eavesdrop, the bus daemon will check permissions with the label of the connection as the source, along with the bus name. AppArmor rules for bus mediation are not stored in the bus configuration files. They are stored in the application's AppArmor profile. Please see apparmor.d(5) for more details. DEBUGGING If you're trying to figure out where your messages are going or why you aren't getting messages, there are several things you can try. Remember that the system bus is heavily locked down and if you haven't installed a security policy file to allow your message through, it won't work. For the session bus, this is not a concern. The simplest way to figure out what's happening on the bus is to run the dbus-monitor program, which comes with the D-Bus package. You can also send test messages with dbus-send. These programs have their own man pages. If you want to know what the daemon itself is doing, you might consider running a separate copy of the daemon to test against. This will allow you to put the daemon under a debugger, or run it with verbose output, without messing up your real session and system daemons. To run a separate test copy of the daemon, for example you might open a terminal and type: DBUS_VERBOSE=1 dbus-daemon --session --print-address The test daemon address will be printed when the daemon starts. You will need to copy-and-paste this address and use it as the value of the DBUS_SESSION_BUS_ADDRESS environment variable when you launch the applications you want to test. This will cause those applications to connect to your test bus instead of the DBUS_SESSION_BUS_ADDRESS of your real session bus. DBUS_VERBOSE=1 will have NO EFFECT unless your copy of D-Bus was compiled with verbose mode enabled. This is not recommended in production builds due to performance impact. You may need to rebuild D-Bus if your copy was not built with debugging in mind. (DBUS_VERBOSE also affects the D-Bus library and thus applications using D-Bus; it may be useful to see verbose output on both the client side and from the daemon.) If you want to get fancy, you can create a custom bus configuration for your test bus (see the session.conf and system.conf files that define the two default configurations for example). This would allow you to specify a different directory for .service files, for example. AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ dbus-1.10.6/doc/dbus-cleanup-sockets.1.xml.in0000644000175000017500000000475712602773110020640 0ustar00smcvsmcv00000000000000 dbus-cleanup-sockets 1 User Commands D-Bus @DBUS_VERSION@ dbus-cleanup-sockets clean up leftover sockets in a directory dbus-cleanup-sockets DIRECTORY DESCRIPTION The dbus-cleanup-sockets command cleans up unused D-Bus connection sockets. See http://www.freedesktop.org/software/dbus/ for more information about the big picture. If given no arguments, dbus-cleanup-sockets cleans up sockets in the standard default socket directory for the per-user-login-session message bus; this is usually /tmp. Optionally, you can pass a different directory on the command line. On Linux, this program is essentially useless, because D-Bus defaults to using "abstract sockets" that exist only in memory and don't have a corresponding file in /tmp. On most other flavors of UNIX, it's possible for the socket files to leak when programs using D-Bus exit abnormally or without closing their D-Bus connections. Thus, it might be interesting to run dbus-cleanup-sockets in a cron job to mop up any leaked sockets. Or you can just ignore the leaked sockets, they aren't really hurting anything, other than cluttering the output of "ls /tmp" AUTHOR dbus-cleanup-sockets was adapted by Havoc Pennington from linc-cleanup-sockets written by Michael Meeks. BUGS Please send bug reports to the D-Bus mailing list or bug tracker, see http://www.freedesktop.org/software/dbus/ dbus-1.10.6/doc/Makefile.in0000644000175000017500000007356212627362261015374 0ustar00smcvsmcv00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @DBUS_XML_DOCS_ENABLED_TRUE@am__append_1 = $(XMLTO_HTML) @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@am__append_2 = dbus.devhelp @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@am__append_3 = $(YELP_HTML) $(YELP_STATIC_HTML) subdir = doc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ $(top_srcdir)/m4/compiler.m4 \ $(top_srcdir)/m4/ld-version-script.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/m4/tp-compiler-flag.m4 \ $(top_srcdir)/m4/tp-compiler-warnings.m4 \ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_doc_DATA) $(dist_html_DATA) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = dbus-cleanup-sockets.1.xml dbus-daemon.1.xml \ dbus-launch.1.xml dbus-monitor.1.xml dbus-run-session.1.xml \ dbus-send.1.xml dbus-test-tool.1.xml \ dbus-update-activation-environment.1.xml dbus-uuidgen.1.xml CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(htmldir)" NROFF = nroff MANS = $(man1_MANS) DATA = $(dist_doc_DATA) $(dist_html_DATA) $(html_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/dbus-cleanup-sockets.1.xml.in \ $(srcdir)/dbus-daemon.1.xml.in $(srcdir)/dbus-launch.1.xml.in \ $(srcdir)/dbus-monitor.1.xml.in \ $(srcdir)/dbus-run-session.1.xml.in \ $(srcdir)/dbus-send.1.xml.in $(srcdir)/dbus-test-tool.1.xml.in \ $(srcdir)/dbus-update-activation-environment.1.xml.in \ $(srcdir)/dbus-uuidgen.1.xml.in TODO DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ADT_LIBS = @ADT_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPARMOR_CFLAGS = @APPARMOR_CFLAGS@ APPARMOR_LIBS = @APPARMOR_LIBS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FILEVERSION = @BUILD_FILEVERSION@ BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIR_FROM_PKGSYSCONFDIR = @DATADIR_FROM_PKGSYSCONFDIR@ DBUS_BINDIR = @DBUS_BINDIR@ DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ DBUS_DATADIR = @DBUS_DATADIR@ DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ DBUS_PREFIX = @DBUS_PREFIX@ DBUS_SESSION_BUS_CONNECT_ADDRESS = @DBUS_SESSION_BUS_CONNECT_ADDRESS@ DBUS_SESSION_BUS_LISTEN_ADDRESS = @DBUS_SESSION_BUS_LISTEN_ADDRESS@ DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL = @DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL@ DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ DBUS_STATIC_BUILD_CPPFLAGS = @DBUS_STATIC_BUILD_CPPFLAGS@ DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ DBUS_TEST_DATA = @DBUS_TEST_DATA@ DBUS_TEST_EXEC = @DBUS_TEST_EXEC@ DBUS_TEST_USER = @DBUS_TEST_USER@ DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ DBUS_USER = @DBUS_USER@ DBUS_VERSION = @DBUS_VERSION@ DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ DBUS_X_LIBS = @DBUS_X_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUCKTYPE = @DUCKTYPE@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXPANDED_BINDIR = @EXPANDED_BINDIR@ EXPANDED_DATADIR = @EXPANDED_DATADIR@ EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ EXPANDED_PREFIX = @EXPANDED_PREFIX@ EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GREP = @GREP@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LAUNCHCTL = @LAUNCHCTL@ LAUNCHD_AGENT_DIR = @LAUNCHD_AGENT_DIR@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBDBUS_LIBS = @LIBDBUS_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ LT_REVISION = @LT_REVISION@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETWORK_libs = @NETWORK_libs@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RC = @RC@ R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ SED = @SED@ SELINUX_LIBS = @SELINUX_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOVERSION = @SOVERSION@ STRIP = @STRIP@ SYSCONFDIR_FROM_PKGDATADIR = @SYSCONFDIR_FROM_PKGDATADIR@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ SYSTEMD_LIBS = @SYSTEMD_LIBS@ TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ TEST_LISTEN = @TEST_LISTEN@ TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ THREAD_LIBS = @THREAD_LIBS@ VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ VALGRIND_LIBS = @VALGRIND_LIBS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XMKMF = @XMKMF@ XMLTO = @XMLTO@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ XSLTPROC = @XSLTPROC@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ YELP_BUILD = @YELP_BUILD@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ dbus_daemondir = @dbus_daemondir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemduserunitdir = @systemduserunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ apidir = @htmldir@/api man_pages = \ dbus-cleanup-sockets.1 \ dbus-daemon.1 \ dbus-launch.1 \ dbus-monitor.1 \ dbus-run-session.1 \ dbus-send.1 \ dbus-test-tool.1 \ dbus-update-activation-environment.1 \ dbus-uuidgen.1 \ $(NULL) MAN_XML_FILES = $(patsubst %.1,%.1.xml,$(man_pages)) @DBUS_XML_DOCS_ENABLED_TRUE@man1_MANS = $(man_pages) MAN_HTML_FILES = $(patsubst %.1,%.1.html,$(man_pages)) DTDS = \ busconfig.dtd \ introspect.dtd dist_doc_DATA = system-activation.txt # uploaded and distributed, but not installed STATIC_DOCS = \ dbus-faq.xml \ dbus-specification.xml \ dbus-test-plan.xml \ dbus-tutorial.xml \ dbus-api-design.duck \ dcop-howto.txt \ introspect.xsl \ $(DTDS) EXTRA_DIST = \ file-boilerplate.c \ doxygen_to_devhelp.xsl \ $(STATIC_DOCS) html_DATA = $(am__append_1) $(am__append_2) $(am__append_3) dist_html_DATA = $(STATIC_HTML) # diagram.png/diagram.svg aren't really HTML, but must go in the same # directory as the HTML to avoid broken links STATIC_HTML = \ diagram.png \ diagram.svg \ $(NULL) # Static HTML helper files generated by yelp-build. YELP_STATIC_HTML = \ yelp.js \ C.css \ jquery.js \ jquery.syntax.js \ jquery.syntax.brush.html.js \ jquery.syntax.core.js \ jquery.syntax.layout.yelp.js \ $(NULL) # Content HTML files generated by yelp-build. YELP_HTML = \ dbus-api-design.html \ $(NULL) XMLTO_HTML = \ dbus-faq.html \ dbus-specification.html \ dbus-test-plan.html \ dbus-tutorial.html \ $(MAN_HTML_FILES) \ $(NULL) @DBUS_CAN_UPLOAD_DOCS_TRUE@BONUS_FILES = \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/README \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/HACKING \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/AUTHORS \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/NEWS \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/COPYING \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(top_srcdir)/ChangeLog @DBUS_CAN_UPLOAD_DOCS_TRUE@DOC_SERVER = dbus.freedesktop.org @DBUS_CAN_UPLOAD_DOCS_TRUE@DOC_WWW_DIR = /srv/dbus.freedesktop.org/www @DBUS_CAN_UPLOAD_DOCS_TRUE@SPECIFICATION_SERVER = specifications.freedesktop.org @DBUS_CAN_UPLOAD_DOCS_TRUE@SPECIFICATION_PATH = /srv/specifications.freedesktop.org/www/dbus/1.0 CLEANFILES = \ $(man1_MANS) \ $(MAN_XML_FILES) \ $(XMLTO_HTML) \ $(YELP_HTML) \ $(YELP_STATIC_HTML) \ $(NULL) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): dbus-cleanup-sockets.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-cleanup-sockets.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-daemon.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-daemon.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-launch.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-launch.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-monitor.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-monitor.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-run-session.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-run-session.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-send.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-send.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-test-tool.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-test-tool.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-update-activation-environment.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-update-activation-environment.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-uuidgen.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-uuidgen.1.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-dist_htmlDATA: $(dist_html_DATA) @$(NORMAL_INSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done uninstall-dist_htmlDATA: @$(NORMAL_UNINSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir) install-htmlDATA: $(html_DATA) @$(NORMAL_INSTALL) @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done uninstall-htmlDATA: @$(NORMAL_UNINSTALL) @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am @DBUS_DOXYGEN_DOCS_ENABLED_FALSE@all-local: all-am: Makefile $(MANS) $(DATA) all-local installdirs: for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(htmldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @DBUS_DOXYGEN_DOCS_ENABLED_FALSE@uninstall-local: @DBUS_DOXYGEN_DOCS_ENABLED_FALSE@install-data-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-dist_docDATA \ install-dist_htmlDATA install-htmlDATA install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_docDATA uninstall-dist_htmlDATA \ uninstall-htmlDATA uninstall-local uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-local install-dist_docDATA \ install-dist_htmlDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-htmlDATA \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-dist_docDATA \ uninstall-dist_htmlDATA uninstall-htmlDATA uninstall-local \ uninstall-man uninstall-man1 .PRECIOUS: Makefile @DBUS_XML_DOCS_ENABLED_TRUE@%.html: %.xml @DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) html-nochunks $< @DBUS_XML_DOCS_ENABLED_TRUE@%.1: %.1.xml @DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) man $< @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@all-local:: doxygen.stamp @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@doxygen.stamp: $(wildcard $(top_srcdir)/dbus/*.[ch]) @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ $(AM_V_GEN)cd $(top_builddir) && doxygen Doxyfile @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ @touch $@ @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@ $(XSLTPROC) -o $@ $< api/xml/index.xml @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.page: %.duck @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(DUCKTYPE) -o $@ $< @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.html: %.page @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(YELP_BUILD) html $< @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@$(YELP_STATIC_HTML): $(YELP_HTML) # this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile # (which it isn't currently) @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@install-data-local:: doxygen.stamp @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ $(MKDIR_P) $(DESTDIR)$(apidir) @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ $(INSTALL_DATA) api/html/* $(DESTDIR)$(apidir) @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@uninstall-local:: @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(apidir)/*.html @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(apidir)/*.png @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(apidir)/*.css @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(apidir)/*.js @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(htmldir)/*.html @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(docdir)/*.txt @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(htmldir)/*.png @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rm -f $(DESTDIR)$(htmldir)/*.svg @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir --ignore-fail-on-non-empty $(DESTDIR)$(apidir) || \ @DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir $(DESTDIR)$(apidir) @DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML) @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)rm -rf $@ $@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_GEN)$(MKDIR_P) $@.tmp/api @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp -r api/html @abs_builddir@/$@.tmp/api @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)mv $@.tmp $@ @DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs.tar.gz: dbus-docs @DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_GEN)tar czf $@ $< @DBUS_CAN_UPLOAD_DOCS_TRUE@maintainer-upload-docs: dbus-docs.tar.gz dbus-docs @DBUS_CAN_UPLOAD_DOCS_TRUE@ scp dbus-docs.tar.gz $(DOC_SERVER):$(DOC_WWW_DIR)/ @DBUS_CAN_UPLOAD_DOCS_TRUE@ rsync -rpvzP --chmod=Dg+s,ug+rwX,o=rX \ @DBUS_CAN_UPLOAD_DOCS_TRUE@ dbus-docs/ $(DOC_SERVER):$(DOC_WWW_DIR)/doc/ @DBUS_CAN_UPLOAD_DOCS_TRUE@ cd $(srcdir) && scp -p $(DTDS) $(SPECIFICATION_SERVER):$(SPECIFICATION_PATH)/ @DBUS_CAN_UPLOAD_DOCS_FALSE@maintainer-upload-docs: @DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "Can't upload documentation! Re-run configure with" @DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs" @DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "and ensure that man2html is installed." @DBUS_CAN_UPLOAD_DOCS_FALSE@ @false clean-local: rm -f $(html_DATA) rm -rf api rm -rf dbus-docs dbus-docs.tmp rm -f *.1.html rm -f doxygen.stamp # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dbus-1.10.6/doc/diagram.svg0000644000175000017500000010214412602773110015431 0ustar00smcvsmcv00000000000000 image/svg+xml Application Process 1 DBusConnectionInstance C/C++/Python/etc.Object Instance Locate Objectvia Object Path Bindings Marshalto Method Call Marshal MethodCall to Message Bindings ProxyObject Instance Application Code IncomingCall OutgoingCall Bus Daemon Process Application Process 2 Same Stuff as inProcess 1 (Object Instance Has1 or More Interfaces) Socket(Bidirectional Message Stream) Socket(Bidirectional Message Stream) DBusConnectionInstance DBusConnectionInstance DBusConnectionInstance Message Dispatcher if (message is signal) broadcastelse find destination named by message Destination Table Connection 1Connection 2"The Session Manager""The Window Manager""The Screensaver""The Text Editor""The Hardware Directory""The Address Book""The Dictionary" dbus-1.10.6/doc/diagram.png0000644000175000017500000023165212602773110015425 0ustar00smcvsmcv00000000000000PNG  IHDRJS6t sBIT|dtEXtSoftwarewww.inkscape.org< IDATxwePBMj]H(]H"A)"  KBBoI r8fwݝ}]s̼͜3ymM$I$I$I26 I$I$IH$I$I$I@ $I$I$I&ڀfClUۑ$I$I$Mėڈ$78j#$I$Iڈ$C$I$I$IH$I$I$I@ $I$I$I2G}VI$I$IM ,_UB}\lH$I$I@qwI$I$I$ PJ$I$I$i R$I;IEYLeyuI/1Sy}Gz0vFel.Sҝey2yT-cwpl $I$IˤPJ"iSt`mI:%yɪ6$I$v64kXLsHUÁm_\=I$ISt>Uݪ1WeOdջ$Iz-֨ڎ4070Uۓ$I>2.I^E$*imI:][Ū6$I$靤G)IDRc,)%µ@DN*I$5PJY xT9a㱏ۀ/uaIؾ|;Eg*I$IA $II)Ӏ%= j;wY[T=큝m?>6$nV%%] ||d;;I$}JIt* \4s  Dh2Mܼ"GaevI30;40ekH 8IS~wo< !9E8-^oى$ITD $I:y["<9o3]u&ޏiq.,#rQnnz;} u>8mFBIm>$MNM jey6`vIj8:~I$IwB)IoP|DS8/e>۟L nDKTW7wwrg3o[?b{w#i9`6xK]lǟKns`Vۃ: ѻmxp\ \XW-?&ovNeXXPz̿ZN$IPJ>oh2- ,L< xGW:oh ݏň<+m!<W$-`~D@Jˉp_Jڪ[2 7EP(iv|'*SgBLwaǫD;_ {m$BMeڢ4o_ {$II$}I3V  e'=D!ρu$MFxnMlXOO \b{'B/W3.o?uKOóCw_Il<_y a55q#q&?s8V6[Dݶo*Z̷pOd:۾K4n?H 3~_gr^B&Xl׵KD-ACUW=n"D *>MK}`i`]tI[cLAˌ)6ΆSܖgu༏!*߀iKq{sQD2U޿sWy=i/n&'{iE"iFn"ߒ6)a9 / ʃ>\o}moj{!%öޖt#%H<$IҋHRJw'嗈 }7קZykwhG)o}>y;pmcINpNm&!UF|«3>e/ko94RҿڛdsI/j$85;K?پ8S҃1D~OI:|(~^l2X}ޥ~G-ޛ!꯯4+|vI^穽%$IB $達U+!߀!߯¦EH\Hܠ}c',Vү)e QK: xZ0l.D'Ѻc>\8?ήI R;}B}$<#"M[~X blXZDy(qJZtH WTO˗^Q"k$IҝPJ@Yn(|o/ LU_cDS#o۾q?$BxB?u Z~;^ @zˮ&jQ6{HZdw7[ouJzAZ(;%-jxCmwe^.!n/[XGx'2B)W?QBV$4ILe$I2G)III:\ē-lg%!ER ؾ/oaI"?I[V_ƤlRIsIZg񟴼[%gc\)i"FSΒ&4 KHUKL+iI+/+,_gDV$M,i%`eoikhBXm$iA;ckVl,ג.v&iqAB/6lfDW%*递ۘI$G)Iq)_s)M}>L~QWcu?ND8/$2M0|YÈ>"蒒_t^9+(a9~@mH}}\Ўa|X<(Աw !0弾$ʈEx*91H:{x9zq+5LK˼KU9o+"4;!4O+۽BW V JxNtm!$髨v~ {MAY܈ȃ(\$mJQ}|[w75K][T`DguǗ^]"ϪUIi]X7B$&JNVu_=U$f$MC$oF܄.II)$ <,,k{oWlV$INl?koi_IWlZ$JIٝ g{/WmW2HZMԒ֔44][yHw*Iv=sծ;sI";`ER$I)W#i"IGWlbe?-xv}| cԽ6K_JZ ]*u` `=#(p(p; 6BEխoL}4ZXNһ4S[؎=&M{r xVDu{?D>\RgÒ&ńO } X)I8Lҿc'%WDT$IHRk;0x[HJ6BDԛb7@ځ ()IuP{ؚͬԇՖL R&Q5 `IKa<`(p[4'6' !1^,oldmo _ 5li`ǵ$i$ !ޥ$:[5v쩂(%=R#`|E&;U:$l3JOݺO[Xgc%L!ȋN> >6!œKJ:ԎՃ|$l-FB(_KN+R(%= I }Z.~ғ$t*y]p#S;oۇESWR*g`&=R~]^IƝ$ PJz}z['}ʼnJ]B|=gB8h [)%$p _muG+ni## rK8jaIRtld$}JIM lH]O3'05q4eOB}BwA6E` ?%7"n>'n/}rg'o{HY/Qei"|~=a^DGJڳg*RI%'!sHxq%h^OXӟLFu5A2b|Q3޴;2> ݬ*ZvI(ƊwrK%iUە$IuPJ~4)=OWlRx f45q!Q6jx=xn3`2f?!$տ߰tʍr1@8o{#I;ߣOӔ i:;DչmE H4єvNrMi{/}b9$DlT;$d{qL)JQ9bi""O͆i8Q¼ ='&f$zYզ%_kuZT#Lxn..?6I&)EҔD違hC)%W/ GDW>w֭{ɚL u4e~.ۺ}_&n` Vq/I{GخqXJ (}0ZEDG-]=_gj(|^h\7w-c BS$i*.j|]P}< <0=jI~EҪD~j$^R(%MI)m<o2˶Mb,XaZj;*UB)bZ Ըn^I|ʆGu/^&eS5 ,U' L\ %iYB-3s?%HF3Rs!"le>Wz]hz2;{HE޶ϭڮ$IJI!ij:a`1l! !%Ȇ~i,:ڱ$EKZhRC`>anJI%?< C4W1wyG>^ɵWqIPD=egk 5݉pΏxz{gy2.lGC%V·wI7Ȇ dj)!.]R$ILpoL\ Lzy؜PdKI[$} ؓȕ:в~`)Bg%ga+`Q$R$b`W"zۗНmWm'ick>Is iN E˴ wpo?ZkTCy/`_ؤ$Rl oB:Sk\? a>El k$RpeQ`%"t%`yʌHUۓ$]E KIe`,ʵ X6׊$m#iLOz"e:@큓Jz?>JT̾~IKITNtv%%G$9$-InmMܐ7>U$A)(qK(n5ӟ%$=M] Y}Ձk%iU۔$IB)R m`&G9+NQ([ӶVA|fޮO.gbv{|U4bYQ’n%B˜%lRz>I^DUy ]nחHZR D2fL1$m  tS??Dp(+%!i*锰 Ȉ[JO$Iz)JdsӾ#i Iiۇeժ f!`&I嵧i$4[ؤ3`n9I>DDs;%=-/m@8i IDAT%iMJ)R61\IF.^'˛\bZ~Y>ϗqMg{`Gߒ'?&$'\^$$irңt)" $mLTzX6ERS< p'p/qӾf!^.V _xSI{D_C: xEyp!G"# z;$iO pm)2(Dq9(A"t[I5O.e:]inDY?Ovin&* Ӌ[+ibI[b-!^.v_$iFA/H\ۀ/EʹVB,nQv$_Gx%w!ಮ?}kY>ش&r%UssqrF?$,ijklF|o4{$I6).܀ j{tL( @mh|Zڜwm&~'LYB%6-Oя[3~W gf ›p1˶jSmNx!'ʄx ]ظx#O>϶ם{#'mNY-iZnO޲} i%MD Ќ\Q?nה%H՗Bmh6³@כX]zg!*yRߵ>`;08E@|Po 5U@Ɔd]Cx>n]_&ip<"q>y?5G6ms 0 QA 85%`DG?-SK?h /wi@k"Rr`kp$-dJ"nղnKs>ߧΧy4^Sq݉ǁ$Vm}GJo$MJ K*)ӣ)aC5kg^#jEie;ƶ[=Q8"CKm_Axaf/^J{L|/Q֏fm%lRv.wtx1?1`z`>r}'<~sc5$TGaB#n*)i^Iۿ&BW-+%-MEW` ^/nFxVj <`᡽M#߳gZ%TiaP{uM gH8hofJY[l*(&š k!x1D`7IW¤'t9姝J 4( ~+p+Q];4@uf#rFއauzo!>.ţ%KGAxv( X/DT#O1l-x!ݪyAd׸p\Sl:;^5Dϕ|Pc\Jx$kŮPK7!j< |P )#zⳜȷIDDщ˺ir% Ŷx0'q]Au53}/JoϖtUacՆ$I2pe Fܶ[{*#tG'IQ #\X򿚆%XHnw/@θ8d<=tZ%$i gӣt.Zρe|4VH$͇0=M$Cx6&=$u)D(ƒw+6(g6Nt$Iu?VNFՆwʙDͺ%$I&P)(i۟K:GGeBҷkŊߪڦ$I(%y TǴm3h8z!Q~yII$݇푶 J d#3XA DHv©(?hР'Ia+4huqLI<JBҩwږo}ңL O31HyNQjC$ؾ XxxLO+6+XG6$I*) e7UmH{9wdw@!D|$Ib{$#i,S$M_=II7&&*j[ڋAF_ڞ^Fz$vl?,|D^Zb: ۷SUlJIR(%ܤ6=H퇫LiJZ[$]v$b{݁K%,_vu˖h$IJɄ#=ěT:i{pRңHBҭnt?o_In$K/s?4<'nlja$3U&Ďa `Y"VITlcc`{I}$G d4&paն#Oڐ^Lz~7w`(p%j(f4Cݪ_a{$Qr~~h2|]IT"+q] l \?෶''j;4?Zo LζL$cloB47d5[N>aD(ޗ}q=gIsTmOңtIfnږqQƒdΪGޗ40praۥiC~}>`CI>0{XZ){Qi`NRҞDW W_D2Xf.+e୶lv*Ż%mnl?RIxh$Bң;gׇ4)DCI(u3MŻ6=F}$$p#>-w%zmKƵ@y7ʲ/s `.3x\MmeG5N:{x#%e8yt1QJ:D1ۆhZ$-XBz$ExFV$ :_Ǝtr7L V%B N*9㸏O'' xؿm8đD^3v HzX8n엒&_QPɄia2Ml_'i JI|$x`v$Io&RQ޳LՆFa'Cz!$BA2Ѹk lLxaON}J)m5)Q=n.slc |L\FWغnOS.P?$|Dc9!!j&V=ZDS˹D jh4#!j^M|>IE/Gl6!$Iҷp{^RgVmӸ=Rq>Uۓ$JI{Y&TnEqH f&ÏՉ!DEl>J!B_/i"`1`2,(qB4զgmLb Ik7H)UI: ÓsHk6~\l Ishq{6 lyƗD2 ir`YB8m@ٚAPn:%I҈g%.=MWmOR(%e๪Gҷ%*$C0'pٹNQ%jH<+ K ܐ}CK)l$i³Zp?'4Iq}2?M&3lڐDz Iĥe{7V Qkmw/ؒu^tKc$3x7%vK|IKWmOk芻%Iz)64-0q i $Mkնt7QX"r.ۿ=UDT/y"J&hIk-"i*IkJڬB6fC'k&I\LLL^!]ۉʯWIP=ޥZm$@ =,@h&vzՆt5t"+lJaR[~ ۛ#`HZC`aҼ$Շ hUu`gGFt8Q )ͶFVmKtze[n{D9wmm'~GC$\,iÊBEђ=jcB)i Oӛê6)O(OT;XZ!zGH OCv&ʷ\g{0%M]ey`eWf'ؾ&HZnhsǶ_?0J'&D IYV30V'("6jX׏rIqf$gpzxau2)R{Fؖa;އ6'I2PJU i`Zm, ^~ZƋC!jMvHoǨƨ\c$cTOMb:#%ܟ_yEO(*%HIoaYO֭eEI9_=lXr[d*I?R{xIp'Z'DF$RCTرרK49w( ӄ7|)hB?8VDDѐe%dpzOm>QaaIJZrJN'R%; I{y,[ Łl/o{m$mAT$ ]CjNNу jZ/Cҳ)U/ *֦g$+7~7%8 A]v ?$ Ip AXeweqMLLHs{nUuOO{EӄAlF%c!S%xZ&m_Ͷ)Ҳ a45xk9ߞS{5JK/m?dz%=y["٣鈩Vf:RDQm)՚QԘX FkDͪHқQkl&d//K˵M7h54hP(C~\ńH͞H&ȆR#\$D,mt!0 IDAT$}p|]9JP!Uږ%" +P(gI/e i`Yg?uY r%ǦzdHz(~ \l(e2dfO 㙜`(+7UcI-DwFGi4Q'ӃP0(G%,i׀/ ؞il$5~m:p3nj{I$UR͞k3Hr;C%~pZd2 {21lNj$:C8r/W=J38 QMQx>].VG OW4mvf{3bII|N(=E]3S%jiiI8SO}(^|o§<_7KPܶImD2D62tR~pC3$\O(mӓ%k_]~%=O \w)<0M40/@Ѷ5V_D*+B2~P. NR*'-ߛQ8آ}IF|).@: J}BQ ہ[$)L.GTX8HҲx pN?X4(m_j5{"Lo"J ́ڸqq>&#KO:k+} S }AH-ۧ#>$n{T+D%Iܸ)J"JGIb| cuj`9I}K}QxÉ0a9[}Zf*Q0!1~pKDQ7l%i'JIw~yJV}_3&鈦{4yU!ikD`{Û=ZȖKRA_ҁ=D1xຨޥV>À% dp/ FGwMs|"(ѰY2vޑtp:> mKz^Ҭ18@JjLqzh?پQҊ1@{l[z{$aW:69߇[\GmGtzgI<$ ٬zb~IjvԾ\DPd$J&z$EkEҡnlco$y~NFJhtTG S-Q#v*9UvAI#ˀkk( Q(qTxI }&n|kc!iRȼyߛttl  <+i]k׎qI̤syxXdz٣鈦z8~5Oү[SXO &a_`N_GGyy)|l=CHED:ג~ IOp3 "_|>&L dl_(d6B?j9͟1|GJCʄ[WK)i0Z 7yL JX)l8%/zl?vbBv! {jvO__uQ%u5)̶d `'{ PV#D5LvB! 'ϲqJq3)iqW" |6O{Qǀ2A)Q~hu `&IuqA,WLG|M\j[5I{;L$)"YZ`;Hlgh"("LUI$/g&yʱ=Ds%^눚o4q&Ϋ7kLo"J( V&${'¡ֶVS t: #ۃl0b Vv } p:* g2VjQ*kw6$~U~D8MdC)l(e:)ma"ic/jldI K:gxX(Jm``R^P94%!i ۼ6뎱%i1I[KZ7uIZj??IRc+4RR&lGGO^%vI{ZaylMF62*ɆR#QZ(cQc}6{>nևg >a}ʣT N%j l\ŀP.j$KFhжxg|q Q\'q"0)!N>u(( !s%U &x|L&.7pHZ fϧ-$M.G>bQuz]=}7+iR-0I3K08B^NPj{`۷)EʩLC>O|^؝WϬϷNp}ঔoQ%-w̶!}c:#$prJ~oTɔ5IO3Z(<|o%ygNv" Ԅ)OM`<ʄLm1"?`lI5Z!I "?LE螅}/ݓꍤׁQ(baiSIG'E-?CKKq$ջkջL}4;1X4+9LKKr? rW%@󚆤$?JJ~w44jL"٪pkۓվ/=Jjh2'K=H4KElӌD(e@@ ܒ#=JEll{GBe aMM_ɋ\O9\LO JjhIk:t$-Jx>䉜iﰽldz^R[$ e%)8oE9n&ӛȆR$.*`%0h88Do|i74G $MRTSS%MqLMzGmoNݗJ,4΢ ɴI62,DF5hHQC?~eI" kfΧkS%(hII¶;!9FBJl`Mluv>{IAII:VcI;I{Z/x3!IzEw:|^Q*bB,I7}oPd!JjhG)Ŋ$jq+cev]z?h|@(ucSDŽ4i$kBYIH;~IJXF7j9B):pkz<9_IC9Iك iqKV:>*?n2Imy_;;P0%DDԷY2?TeHI#)Nl:> [%휎KoǬGڙojR^x[&LbaF D^kxLo#JjiD]C=Jix`$P$Bh޴Zү=Jąǒ1&pӶ*~+oboѺQ\yQDZQp3g4 ̵Ԧ\do9VjZ&C$bqYۯO;z<4֫ ldzPTK# BvgloHئ'ȑ׀Qΐ4HRchw]lJFK9'v' p88&0h`.Z=7&í"?=]e/=r~W\o KǏI{{HwcdG(O"I7xոBY!igYx>}Z8ƈ˥Zv}{"d}Bܡ#`|?ۯTo&9R Jڈxv{yytBҳDl&)#enꊤXeD5# rR~8H~_&O?'=J%Ѿ90T* `U0\d J.|W<4$?))xȼT+r`mTvrR~}X_zJؾQtxɯ=Ox}dz-9.Jt԰ 4*?i[[ zH8v[ug:GI2D(D>B,bY X179$MJ.Lf&O)6}ڣT$trub(pP[U=dR3S"|v"נn$o!&wI\kq# GT`F"l^B`c"'m|1"m.ZW{.3Exj\2=J%l_E/Ti1c FԛW L&S {2 `:=_g:l܈1L(}7p7m6f'Bx۟~Ez85,=IKZ؀OƤ ,a旄`۟s7#Ɏΰ=Vi_'R< `ZnIZ؁PaJI}^c`H11p{Sݦ-o6;/40\I^\G_1 fL#{2Nb@Pד NݑTR[I=J|v'>7$ l &d+]$U:(iK[z6p090 01pa-aDAIB^čh9(ʝOC i}%  CjvI ljiCIほ2gL(}.?0"ūֱ35`LW LgxSu{Fƨ.HZ^cڜ(N?$תwGc[szQt^]*!m0PvG}A ~A $ ܩ7b%N(aᩚ(~ 8~ \F\ް!) OuFUgi+w~(s+R ۧ a`VIsש٣T J=xQ#ꆤ_7G3?#8FFOrp=ߥ)O+S/2-b=yn CxKdžS%rJ7vN޳zGq[9BA(},`kݿ jw٣T Jr:;u(%saUMlX=~QÀm=LuSn"'iGj3N"'h(Pʁ0-2K:D(ӄ DDڹ =i뀷:3ӳޘ:jEJyJ${2 dC)Ye(Hޠ' Dxv!q?Mj P2t+p3ph80F[QD ϐ4,7HLG 8 na V4e.=JL^L I EV?eIcK`5w~b{z՛0zbؕJ IDATzhiiXYr5;f2KKK*D]~ZUÁl_S~ g{`=N$ e _۞Yi٣ɐyXV}km$%]G#i ppp6٣OGfWAZ~C2 dC)j~W˱%rTsR0B$bH=eLsZ;\GR 9Ll(eV^BڮylR{)٣T&+{s4Y1d҄vh:P@*e2eʋuK]ji:B(YN jQ~D(I:UҌ*lgkts8>BUhz$Iz\:w6v4$ Ξq|QJߥISI,-. lC잊/׊ek_9Y!)cfO ' 2 at Iq5E `M`TT30Ni\2D% +D1c P1JwZϯ?LϿ4-57P:pؗ9MKkMKǹ nj.S JEn'IcM,3M y "</ߟdIhf7nomik`@1}qecw7oof~/-%i>D\X*=JLPtRR-  d[kFZ< X7]ġ5죌&ǯ'aL>}r/`yI-47{Wo*uK}8^AeOtp!N!n^t%#oCQ aؔ$'<˦~// wI|;;1gjp!`¶aNHٗooO]vyn9/mg<1T|>0+0Ga[/iZGmMMn "vA${22*wZ010F}r(v֯U߅7wߧ_{loQEGl'i5uQl(izNMuK }P`wIs @moF_3H?9Y{+/`Wۻ6G۾\I^4`c&dF=!As^ǀKhii2Q{RV:x/Sj8-, lXқ(ɀ^53KnGwU$٣ɔ LW PҀxmjzja V1G3<uwY`VI{!Zڔ aiIE6%rKT2YǓ~+)h `-KIoj Oݥ!w$.}nkR'q$!&p:(45}/gᵉ:[60oa^6p9?ޒ4iYLHLhL7/թF]ޥit<G' i֡vI%+C߹xzdPtˀM龡T3R %Q+B}EG{8CY4A3&jjw$nȎ?IWHED^in=%]ؿXQ|QJ"NNLjv[yn&?& aW&N:J_%OOn!WtS%FJں^g(Jt0tl(emft-=Jk9KJ 6 w=Jل s2A{A `nIEtےVV'nR4)pRND>R$cK}xٶ% MxJ7[9|$iE`]ۏIM@hfxL}g: E SG)W:J!i`]{/IÈHK%]Äd=sLl(e%}@ߍji(m@$wqIV٣T?Wx>H.IA{}Uxߗܠ4ރ3p[c}E}"o_#)GP!Dܸo@=@-W:#=Ja]`0$yd&~Δt.pNE{l'i.vd'Ch3Lg3r";PZJI6bBLxF5yL dZoۉwױ}{?}_wIY)lV-i.3B]pΩh͟d2dC)}.6fcn?'Ԡ¡DMU9̒vt RwdzIt}JR\jt^67MۏWNOD N>MֲUPߏSl9Pб9#"pyy`ZN}N lg*?و/Á+=L(UF"KNv5 0& ͩϰFkvrjLQtT sjIjTC-BH ]]eObUf*=JI|v$n' L$LLȉsWs}iD` t|et HvaXTﶓ43q֒ƙXA/p p񽈰ksH8g gn^+iY <\>WodMQӧ?'o"]%D\aDb[LM~H>Q*'-LDS-؇Xt؁SM(e2 !JZq]Gn'?;ڮ__(a{;h~GzC7K?k109N휎Zxbw&uo((+q+a$Eܜ^6)bzI%LDq9)q]ϰ(a\>H/N̔<=$9pg5 aSھknD}oeɋV /mפv/_xIDU$-׉/# {tbPLl(ejEw>R YRvu~Q _ψ8bʁm{W2>86W?B-(}^hs3a$-NH9%Ci8aR4Ms+RێXKyQ7%ah^齏W"`U="bxSZ2]'{2IG3"2l@O19g$(ez5OUj}Rĵm2BrIZE}D^ Zq!Iv?P7:³3Q-gqղFz jF(e2Q*)W901Cحi!6Xl?$3L"JDrDQU~HTKn$ڮ _&%I$-' Zl7#`m%S_xKZL, Ǘ$U+٣TۣlGθ8] b^d&P4/EfgB'wX݈U툂#Ӷ/62%R_iWUQ>$YDW*gt|s:!+٣oV"V)invy[xwd'J$Nr9Q9i}`Ӝ[sGѶ}%~u/}Wt[$- i IKIҥkɊmhnX%*fIg7C%"NIJ3}6c%]8ORx"VKH2R4I+qGH:3I3K:G~f=JdO'ć\`=!v-dڦ2_`[}+jX+ԖCz!_6{"Mb}fCq p Q5IZ^¹;yv_O*iuROHZ؛J&?3p"6 np p$?ھp$2)h}3=$E.ZxVӥs$-k r?2'{D$Dw9d2${2=zH:m_tvLUkm[eɣ9XX&{˔$iU"{bvvIrx5"~lZ!پ0c"?&"*/DnђLWbQ"pTsB!i l3/ d!BvDaܴ}b{|gK(5SsTD&SG)#Ntsi>ݣK V_+i Jx|-[/LS(?CV/;XI$<=+ؾ\u~KһDx~f]%0&޳#yB4 Nl?+i["ijGxvv# Um* D1ھ5[`8%uӱUAO!'%2=Qd2} /p|ms&---7 5L`PR=k &ԐT$ď1_X"irc:jۛ9J#.;,hfz0=^Dm.iJ`-xZx XXh4~@fh4KM(aMKLB|4{"A6zF;͞HWRi S޸Irlj7ʎEL)d˳Jz s^Q>"9‹0]j $$ !NdzʣD\g^jD25L\Z 2n BQL}%:2RҔ#*yj״4Ef4O 3 ;;0hvڞܔR{%ӫUw9JZ BvCRL(uC%5:b~ w6w?I[SIB!^ r6jgoK |VCHzv^O(\Mwlл>݈3mdz?P9%I2=Hs]+rR?e$= XE aI0*,^zrkFBε>V/b`ZSx]I!{^fXiLWy9J[yHFk9JUz1ӝQ/IoKzK.Wz͓Tt]RҭhIHں;}IE45 Uj+I]냂QqE#^{IYvqU9LWyhQ'J<]Kߖ%(iB m^tn*_ޕtYqܞSK(${7pL&{zQ8fVN?6/KyOjtDʗ??pԵoe絛]}Ku"9G)I!ī7{Ы$ Tw(mt DR&*jTG)ya_?pai6Czu\F6 <#9IK*Q/}G:oIײەjIZL|ݒ4G$<,kiI$=&ikqo%E,^0CT@`<5 |%v?xCJ"gauBxAWLlX)wAx,&' Y.D"^;Xݛ|l?EHg{EǤd "B`[qpI29>b{1`_MWt(!q}~dK(њtP F+%JUW shf4^YDh`4VDI HײktEi-=1u\:kS^9O4#~w=/QGyG.Lٲ(qQHx6%t[Vzs25%J=.(U" !~$K<< \O\© l!i/Is.o2v[T,tYǦXk[u`dlQnU8 "4* wM:HS@*) O& wMz{N!]ÙlNSv9ykϬYfgֻfW6763R$}^Q>J`co?"3 lUR" &i`q aѲ} +(QJm ԟbF *|+uJ^@9G` p% ~_nkQJJ(%{LweFHbfi]~ @I<Jd{/",b1 51VCk#s|9m/mWEলqa>ڶ|8)&1~_nHOV$&)V샟ҋ4JQo>UޣsIڌx*i>]6JǴ%׻l$>MX"=( kخhtQJMjzjRik"u1/mp+ھ.ĬUkt ^>ʘ &(eUkeEyXc>$U^AKZ&gk| %'3>&L3?"R|jF$^>i,%&[-RuDh{J{7Imj%VV,E_c{w᠆w˄l| qRlRsn-f&ֿh3P0zQ`R~pDE$@\`JI$"\E y{fQ:AhŸf.W_Ay8kEŒ?e."&&HZxLh6#!Bl_+vŸw5`[wKNmvGv]fIw)rMILFozIwm_KtgI8Àxkvc'}nD=H pTC ݋xx^:sbonȝRըyxUED{jzE 䣶@<n=/+F(ν[-(ۯYK_d%UU׶0!@CYE*eSؾl X0$M ^$IW&|w:e^|bNYx-W?¿k'? =U RPjUR$I$IRPJC3}$䣔$IiRsH٤shvn#i%%3Hڪ}L*y$Iz"R.H"L(%M%CS(5D2%$ΤG)I70!(5uD]e;`&yQzΣlC_Lݿ&owYGlA~|j6!sTIl%ND 9siʾɁ݁'3m_XImD_D dK1]V4NZ݉z"ea`9GJx=)#雌fdJI$ˣTjfeo=(ڟ>BE&i"` #m*/[G@D}_и-BN:a?"SAߙSd٤C(9] >a`;DUK}@+c'›Fۃk H"쏈}[~HD:OB%*?A>Hؖ=>Ϳ]O SnI7y'C#Hا8oLY}l:;L!|B|w" y_ hxxs1q,0H {wm_AXP_*뿑4'p'.>׿LX  l \-i2Y#igbpZݟw={~v/F+`Fuە9kOW'ۗB7faWȗ.w~&^ /'wQLK_֙>CA>x؝ \GF'>YҤn#}Jۗ~21Yʧ%n?bnڥ;2x ZX*cjoG$? -Zu0Ʌ/".B!}ÿd=Gl ޖ4 m%ßE%Jh~D 59p1lXQ12fve^+z$>CYd&i)0YW-/Dh3vG-m?Q)؍uv*g I&5  &B)uK$\^H|CW8Y]I^ؘx^lZo* ℾg9bz3XuVڞ1xЦ\% H9tȺ {rzK~W#~siri*NiNIC+J«U?B_syPjeSUDh2RlR[]eVEDVA 6M<|W%hoMK<]Uko +jvvU.}s!sO` dZOkeKԎA;m~@ &&՗Վ[V.ھJe#BULwIJo<||ޭ;v9f*6?PoxϛC6]=V[ߙ@Xz 0EicAB lSS+w9nRgM~KjV?riB;?P_}oooĄ&U}KO݀ߚíOL0?>ku&w=ޜGI$-L -!f?_GHڠo۲$I[KZM%}Wu2R B0?G=]3?MK^mi{jŒ=߹R2Rl7{0 mGhCBid„B=݆sٵw.]LEw"& >t$>JIsiJ-p,{Kӿ۩Zݏ\v@z+Uw33C(&YcKGM/pb}m휗cjyW_+w~VfYn)/7\ϝ]7[VRvx]by !mPnz7Kþ!چ<*Bq}G>~аX+wf:Y-_2ʥ녈^K.Mn'/Ͽ)ZݗwizS}]e>ϜuљٯX@Cm@h!&4UN`4ݎQ1+mRi/ BW[Ҭij1jvg{G?}kQ˒9hUUK/F;ubG㙉k{B4-%W-}X6-Y lX޷=:ayl* 44!JIS4'I!`7{oQw2TC'`7<@%MM%9ofReJ (}$I$IIR%I$I$I4R$I$I$I1%I$I$I`Vwդ1ju$I$I$x]$I$I$I)(%I$I$I4R$I$I$Ielu'$I$I1d$I$I$I. H>$I$I$IWIA)i:lu?$I$IR4$M l$I$I$IIA)i ew)I$I$IL%Fҏ緶GI$IIju'Q.#ij`=S`V `y[ٷ$I$Iƍ-m$IO$5JIw3C`m$IWp=p?$Ij"2?f~8&4r.IJZ˝M$Id lUҼ-R(RPJ@7G~zNn_N>!u_Jڣ H$IIÁOՁ%m$I!%a 0e ԵJ;m6p_V^H{uf"Z1.`QjۗK/Ns&ILOm$$M"鷄lj= ߇~]73Cs'Ig'U;~C !CiZ`'BJe< DI:x0q+`{"rރgI?GV %;۾MIK5 IDAT?.v}?V(_ 0uvIk[& ۾Cz(,vC;mWfw%lRRj]Ckkr"kηv!r)HIm-B}[ȯuk9O?w>'I$a'I?}\o󱕗dG6oS&k'glwIP{[6!m*6W$ݓpJ~db`].m=rHYy)`!B`F"?kJ˳uDߗN~+i܏302d` !,?QOT*E?rΓ4ky(_J$<2CGIڲHv DוJk8~py ф0g9vr!ޛg{+aN$IL$%̶),2iww{TD6iB՘9k宱 IIG5MC"."|-I_9G\n4K("ݜCU҄&3LGhCmMl?||-N }mkU`mVm?M5oUwtK1Еy>+k/=ؖpdzniw8-` hd)Q< llJr|x"I3y>({ ʌ׊@SUI~0{n-B$A!w !@ D9ICŶ@޲ gnWW wv,ڮ"şyM"8_|x箟P6{?Iӵש2᪱$j"F kю*_rܯ~+I3Զgh74KƠ_DФf?@,X'K:+5;rAh*ꚯ3?ڄ\GbW>5`ABh% c4HB>|avן0϶G#[-ʄ9 lI?}xn=UNe ..0پX k $\^(YddE{(6!&)~JXغ}+ !mRg#9fǕsU|{Uv/mT>~Z'#&!r@'۔::_5ӬH'fkq:ċ0I$i1p3B[يmW F'*OJ%E/kJIHHX7fn]&u2ur"e?X4?!lAT)KVAX,Ah{$y %.'!1O"L(DXJgx pS YlP﫤y :*ѱ wI%(O~%N#+<[Ʉ8n'|Y+EW;y< $I$I$?AԝJ:8%x"*_wDn/GYtkV)rQ<+~Ń;K"I$I$PTC*"aN׭IjRPJ$I$I͈\yKQ~b*IG JI$I$I4ᣴ:p[ۣ$I$I$I;7*iV)ICj$I$IRݬ`V%IJ JI$I$I$ LJbK&@_$ =W;$ɤK񑙭H1k=ӂR$I$IWD$=뀍:{PsH$I$I$iloє$I(hu?$I]Vw"I1-0; ]$I$}>՝H5H;mYAIR?`r۟3~_Ҫ>=Si }I$I"wJHD}hoH0$=4駒Lllwj\KR[-;~ߥ \[Qٗ۽txxgǁ:x.M<ܤ\=ޜ\r%8L:`7L WuW(ۗN*4=KMKoUσkƄ(E 4@,G7 IlJ`ZwI3Oea.w&fA/K  | )rnV{ $ $fS`fzalICk?FSwz`kZآ]X$I% 'SU㾲]VIa{`eeKh~Pl?Ein.3};Ĭ9eKˀD.'wz_h (`Roղ5ݐ^&fm$KBC 0o7ژ-rwE~x[ 83Brx=V3p[wj%Br}! ה\rɥ,Nie0SKS)ʸa@2.4A41ÃK 6p<4 05 pMbwf-o7b+`j`qa`cC`RB[=b@elok{ wga{lF3Kwwm?:c@Xߖ}k~l 9i ?㈉v5VI$I2nhUKC=:49LLA Cׁ۬Ɂm?g~ۯ_+uN}!-!iZ{ ?m_N~+#Io[x%-$m*ib$-,%I P\kwjB8~o/>~oX늯&7m[f40p;;wI$IGQ7L$CҀ2n}I>*uߤjORB=ZxmG.e}x iB]&mB[Iϡ*/IZAߗ}UʏYA#Oo`IK*W$-$ia7Y1|~HhV4/]f$ItAĸaKzSnIZKKÃ۾KҙN#"mEmE<8>"'P7''yĸULz эIpi̡!Q/s -& D8>I{%MƾF&#$Iq !$Mt&5bIIaB J7!_(fNp?K:xg֤e]|-n/m=U7M'2໦{90R81ޏ0iloci@ݒV$?`ބIp`Y"Ht0BM-u->;mUα5m'վhGW%H$II=&RE2[4W<Ǽ8qݮ:Kڔ* iaBy@1{,7}wߗzumku-,s5I$]Ah]o:FLED>IAD])ʵ:۝v#we<1#SǶ91}u\7E>d{Ը'U^8O$,dtG'FD"'c\V L;^q!mCC'I$>q}I }V T&4^$&տN$)7n)ㆅsm_OB^ g Rl_y16Hqr9߉ G0:BE#J; }.(gi"k"3~<`1$l?B8ʾyWʼnE~ ̀kS"ăx6ǖ6G~p*?MjkѲ~dl(u*Қ04YyYB⿋0oK$IN}°ٿVmxU,.S2qCNb g{x/'a{(e2Vيޚ^" _\nK=`;ڸ!}*QO)*IG^J7}c9"|󪝊M-_ \ |8F^O?B(_f:ܡZ[Ah^*?'ڕmZn(֏(70uPˣCf%oJ: Eҥû1Н$I4n(kRvK*IiPY8J!6"cFk776׾jĸe:"ZrgcLaoqS\87 %ӀՈYىol=2=[}N/BMQ588H+k_VW'u ;p]u~xW%U=ۇ$}86m/$]HY7HỌal۩eiaBV%IL {y~ZE]DLF9G kYugmF~QK "KL=^( '&('C~\\O;Y,"!|α}a 2q3qpG|Z{W*#_g%(Ym-Clo1&˶ݮ 8]Fg\]%\SV IDAT6Mz̰A b R#nHZ&W$~o ﬕS؋aOUDye{B`%z":?nA) a?B"l+!m*&s~lw)\Ѧ =3eesU?IdB",ӈ]']|FglV?%mZ[\U)mXL{x %-FX|NoQbjUcIcy޵Vٞ'&ELJU 3lW+KK#k>DDF D:U6RPJ$IO7 JIL!(Mw,QJz}G)I$4G)9R @ Jͧy҄qW:wrmDOo abrx,A !D}Gq?`Rƀ7QJ$Iz. RS8UvCʻ{o`}ÉLq+#"zތ=a%,N%#Ʀ~웺cU"ѿl$IDMGv6„$( Q4_w"i>IkKZSm M{\D$)v "F<|%4c&4*gÁ?.yzv(o'Rjt~֯pfK1fnQ4WM6I$Ig>J%&@lt#. rF[ZDY#k؞O@X\\w ץ*DX<-!}B$C^{R$-BFw(M ^/3>H:"~X`"ӵ6%-< lS7iI4-ʟX!OgD"͈_O`\y>~l$iHZ&I$At/*D)'lX_>i7Oh!0OI:DҜxfjxuQY2R M:H19qczxa>p2!ȸ}V$h&3ժ|֐ r hd."Q u&0җW۟Ipa~p8اYd$I 5Ļ'(5R7Tt9 9%?.7h35T{^7,N1Gid;t: bt*tqQ \'\O^7 X @҆DV?F?4T[l_>d'$I$4.aIql׀/сS,(i۟amܜi.7HAAU&ݔ)_IڞX^$ !4NO+H EZp/(gH:PnZII:s?3g)o$k~/z۟N~6U9$-[e&O$I& %T5e² ikd9`%}b_}$LhZ:z˒.-&?t apy]E5C=lS =.p+'ٍA}IvgJ|uۣmp؜X`ys Qe67#oLlD{mlK_СJ,l&% _CnR椔RQJS QrDa{a3l(khjVj-k!x8SloIԶU)]FG)5_R=$uv8|]EK*QjpN!]v1dfWY5k՞RN܅nh(+QʈwX(Ûj2(uLYTrngIURJ)*(u 9Tb9IF5JP/[ZRJ)[Fc5JCv4v"pe3O>LQoeogͧRy^J)e>Jz;o6~ }}:(U>3` 0BX5`)8j|QSJ)JOYr@]`Z#Mpov6kܤT8u{#pxS6fSn8RjC7M)9co45.=sSJ)څ(_Z3-ImmJJ)Rj(Hq8I}fe{RJ)R㲣ΏZ'u87\P㶤RJ)F䆳uj۔ј٨<xE\fZ+RJ)U`fOOֺ2εnGJ)Rj\NK)RJ) Ӽ$iIݧu#iVI9K?y=$:m[J[%6{tQ~?IV)v^9y%UUsIBz}̬0z7HZ. x"3{5Sj7l$;kgL]ï27%K {Sl․;xwvC|gf$@l}#9$if_UicWxg^3YF~߻;Hx <z[+%G#4ǹ}ƔRJ)VQ;KhQ$ ~,nfwQYcfK x̆ņ}/[p s❢Jt׽^5'A#3ٰ<6;qxG o1J>t)u"QZq܊wG>޻f6HGҲfvu}?$cI|TIRJ)VF:ٸx>+]tʊѧko-WJ;Tي I]Ѥmh~>eVu%m—U߈O?_D>RstL1֪ |\ FR'IKKRJ)R=j19R6`LI3%k>戲H l?H:,O8܅wǾ:ƧTdfCG[.4!?~ND|-T;%efO7%K$0Fk3[4pI0>c5rX3DQRJ)R&:JzH 9sK:X9Nűj{&!i),vu3{̶LHKR6TKH:iH%8IgIڡ߹$+ /izxoB)o[9uRJ)h%<5M- ڇ7K*z0~ wE=s㡦Qz\"M;|"8||ҵ{cN ukgn| \a[uRJ)%IkJ:Άoޒґ0)3+yRGHKҹ]v4D`I['^IHL’nt`2fv:%*nIJ+ G~cܮΔCԝ!~'[fofWIU IrMs~oG^QIsfI E$cJD% y#o8H/iR] b+iRJ)4QҜ&J(ЛみES+YPwx 0?𼙝$l`_8>C5BO:xfs ZQE}hסfv<<#1%R#iy|CѽjI>:qK~gf_F4!])mU|u=Jmf_T9F7xԽ{_ lמlm43f~)<1`ٸ%-Jz̊p)RJ4Q64 (6Spfvg< E7= <3Qƙ Z -.$-ߧkI1% b<,@|hf|O%hO֚O)R.br355P3/H]$u6,xqxRWu*J^h|ӀkIWQCxΚj80쓊c{_*j̑#f?Ifj:\_*m_z_?F"W;;4/xiw㞾|〧+usn:RJiz3;JfEKV)2X*֐ TD||:6C%݀O7yM|ҵ;W]9MWFnq".fc_K403'Ml>JꁏJ:Z;xde(x/c*O6w60Q%|}35;=I[ ǚGf,i|*Tg|~K<^m$uoWHޯJMdfKl yO;67PI;-v~We58`#3Q0o18 n:s\gn|}ѿiyC/{ ƙI[k!&q6jRJ)Mdf;A ()2At`N6>->̚,H*f),#Iaf={Rj)F83_֤jIR_|M\SizZ8>RG60 UK)RJSVS93;mHmmnGJ)R{G$-/I{ۓRC$m"dIGRJ) lo9@RI) 6G{)RJ j%3{̵LJmFĿߓkW3{MJ)RJ %38'^oRJ5#i` ⻿))RJ:LG)*66L- Dp|ےRJ)Cul Y8mI @Ҍ"y5w㲔RJ)T.6Jے^1Gk۔RJ)Tdf+"W-ےO~RƤcf6֍I)RJa;Jf6 g?ŴMJ)Rj:lG)Rԥ-I I=jܜRJ)4:zGi  Ҵ{|$3YƤRJ)%3\kٖ4} G2ݥRJ)S.$XˆvH%RJ)MQ2W;#y|-ے:6I#"yQhRJ)vwqD`KI׺1X]㶤RJ)0]tIPkfqR#pZ$lf_ֲ=)RJitu3;8H[@_`N3֍I)RJSg(Ԛ+Z#RJ)b]J)RJ)5G(ui93 ]IRfoRJ)RIz@}HZ*z>GX#K$F.$ip T;folIkH-iH/D{{Y1tH/N9Fґ^8sFzRF^$=#ݭT"oH"|U:[b-ҽJmY%‘^:]Kv"#FzR9D){VSJ):6QVl < \OICn$QQ5fYҬ 4$U{v,竖$ijC{,X]$VӦi.ھEǀA>:KGRWFzH6sS#]/֋Mz"}@OzFőu#ݵtwBo-7Ez]Oz#Ho+KaI)RJj`} X |IW_e/wΕtNã}.GސZΓt[#P`0Ѻl7q"F; (iV=@?I'Qa.: IGĹg/IZW^CH_:HH[E޸H*m)-R[nKQo.Rcі{; -= |@J) b&܍lv'M^P:wI?/f|HZRFll,Vmdj%"E=e^0SӷnG,2%mlXϹwMv;H6% n`fo711j=C`#z@3+:yǘٝu6ƴ7ow3"})fЭ1B IDAT̚ssKQUٮ"}[2Wnd 3^*NzrήCU,S>-*lTG0s$Rj1f`fRxe3lk6{ XDR?3{PAf]#U5W2Sb~`wKnfj yHUʼ倡|Ψ~n1kRgI:J$}Ҝf6\IDZO?BLLIWY1y3-sy|C/VKsR7jHnJ)3ƶ$Ŭț X( p? |*fzQe وE%-,lfkGGG缟ٰ(yi^|#kRj2'Cf6t'EQnI`twZt$i/S rlbOSUsй(?-2lGDn`h!viEmf8;"w<{&ӦiƛIw^,R놤RpVN1Ӣ6?2і,S#X:%cu¿.ŵ+_JU: `M`Q`I$ 'IEv)xg=r 5b|jˈҟ%4,Iƹq> {<щ?qNo K}8R7ϩ[2I㝸nhQ}^v5Pnh3۶I<c,RJ)5x'`IW8IGE  S`?3{C v=I|~"OxIOٳQ,#fvO:?Z_qIE1y)6ox}3R:J.5$Hz_x>zffwKz(BfC$Is}Y`*æj ,rdw+gfG@rFKz د6z7^*Rj>3Ge|!֒^. ă ?|Zxea|ܓU `9;5E1&mӬ71}ZC^otc8Ksڐjwz&FYS<c(ү "oDH? ؾJ}a=CKϟ(z2>O?E''J*z>km| ֧RJ-I>0#.pMBzz qLdDL@'3mfKf0; ?gԕ[і>fv|:[5Ӂ%]n6w+ ZtJ^2/Xrَ}k `=&mQtrmQDYVˆRp6-_2߄/88+g4ILw; x8F#ҕ;"swH _Ѥ%=cfJMғVe 32c$ϞY86w$= ݄)gWA.vnlZٲjfW;'(IC >ZҞ1RU"֙D _{`I)R0k% ƒm}SB*eV3_J,=$U$tC`eM娮fv>p~)o* ,_筸Y*9#*glW+ޱJm\(IZ_(w|I=5H 0 !kQow<ʢX 8hQv'rmasUwǿU> }~gefE߁qlo|N i'T{EwjڊRJR|fJԷ)wbz+4iۋqT39uMw UG!$GF$ ݒV'xǨ۳|a?cy7#!_#8wKZؔ (+gx\Q_iTŏ҇uNi+|Gi(Z_FZ!RWǿ/uhS_6+ GMw3I/wGt>޹t p?2"d,&\ _ *>zuD6#xnx<5AňZxXsIWi\qx_GC;(ٓkIaf^MRJY_p5(a>Iٷmt :ePTmTE7|mHtaċ8k~ /}p,ҭ"LucHՂ?\͑ZـS.)}o-`WF5Eۯi Q6KEҬx=ż›ҫf6 u4W#yJRbS4<r+Vhfc%IRIŔnIZW-)Sː):8I˿ ~|ŒVķ'4W-uy:/c/S*aD?plI'S7x3{f"b|nf#܉a9ه(?ĞJ%`)Cbf#$ݎe/z-x%b7mnHZߐꈟoCzw'c\4rΐ[hu,o{RJgǣ_lfKzt̮t5Iz̮zޔ$|j_SŮp*iF3Ǥipi:;JR|Q}G;W?`*e+etx,@ԯʡW**=߯ېg[92 >cuS$;UAN3-i|zulI̞FoQkxRJiJ 3};@K]_'ķK$i^ʻAU)M6QJ퓙}M" cI ǾpJ/ozOLQ$O|"xP{_}G5\?f"3f6yt?}% z03{$X1IZ_IsX&-25f4]ΦR7glO{8C҂fKI{2i}]lICS% Y1u0YG)n~)5=QJ퐤%/ SX=ީ)vj|X[|wu_]PRtco(ϩϝ>;a_/@'<0\em'i㵛9'iRib[&ngJ)R۬Tz,v7"`00/}C#݁".|yì{% ^y'/ _BԵp>Rj- 8\OэNantp]z6Ц.nNE3t>rπi %> `@30]߁o:&pa_Ae~.7Z>J?Mbf=Z6Rj3{2Ԋ rT}Lǿtl}W_,94Pҹ'H?1ʼnf˚%U Zu)KS OSᥡ:.H1e>+*:E'eb7T/MRg)RJR#" zf6Mjl8fB+tS0r s_Ԯoc^*]%-+i9I;f 8D̒!7f=,HZEO"8PM{i ~-f묊uIИO RJ)QWDH_8xQ&7kr Sc0ز+;H9 %O|I|3MQboHi>lI54pqxlO4|ߧ߀clCQb;NUӘbϪܔRJ)Nv>iVƴCݱNU;};{XYql`SYǤ=b4ұO WlIGS׉DA`f#){/h>eH_UQd |ސS&~H)RJQJRW|3Tmk'3{H*uGvq{&;o4%A$OϊNbJ)Rj@vXzf4}53P:v py;OTDjfy]g 1mفSQa8ȎRJ)R#Z,Cl|E^"s!5mE;&i IIz"Ӏg6IZT@`z^#5֮%@TLI;5WnHJ)R{b#Jf6V%U8Ik>qsڳ@*~ ,of$ \/i%فKNCe#SZX8wW`q`\DhC5qxو9cţo3I]\WE3w7X ]9R&in3{?kۧfN}P06V&RJ)iw/'~O {UTyg\E~?<`rguOYt.4 7Ml\ݾ x >< ²s=pcI8CI;}; ,n=G{x_󶖤Y pb|;N?p|E6ģk>l<}̾olJ)Rjҕ>63ߜfnkٖ. ,IqyI/뢣4.IxGak8n/t^;!IffGn,41vG 0c+"`m3ۭ~83{98]ROoJŞIr]KcKxV{5Wa0)RJ(= Ojƶŧz=ifպ1홤EcK'{&U{uGU s3Mc`I|ZBE'g o 3_ǃ|o{]˻!6fI{sᣭѴfr I=+=icx-z?KxtRJ)R hюR O%FWԴÒ4Qf6^Zxh%p>!s7 J)RJ@ F+^l[MX_Ssm(3[ҽ?$ j}@N)RfC[Svdqh:?6I _VFa3@Ll i6`6b^V`fG RXz~uQf4zi+RJ)ډ麣߉Բă93պ )RJ4(F~0 1g83(&M*-t&ٸț< [Uꩿ ЩǛzw]OkQⵘTעZע)uC7ZOjG=6P&RJ)656f>H/u#o"q8-,P]T+;+VKy"P); &ubv2򖉼#=Tו7z(յE٨Z􈼣"R]E"H/VۮT{TאȻ7}kfʥiCO,RJ)5At$,Y5j;`xC$#i+IN6RJ)bZkLԍt7O=kH)|sry7KyybKyFcWJm){"xyJu ʛ QKylӁL!HQbCkN.c5\{`p l8U"RJ3h V`[l*efT2;z㝸lZ'Z|Y0z4T>Z<׮5)Z+wY*#JfЯ5N%i[h3۬rf8jWj1f~CeSJ)R+uEk뤚XX g2T͔RJ)TEkQZB?nRj^4TH:(3[lZ4,5xR)RJ 7MgfwQ7߳![9,¦RJ)5Ckuv5R6 X_$'>mfkٖRJ)9|G*ĵs9jۜRJ)Zk4~eC<+}}'i_༢ewLd3|Dl2f@Pס :fGÊ=n~)io3@ҕxij%mcfcfHuOA[O%mG[p pm%0)3{%Ygf4ul'$ 1AnWJ)R: |e?$G<,'i>`[[<p+)z36n9N/3/i7U-3ZNxxh5:xk7$tr=+F{mFs;JfUtNtsFzL)RjZeς@̀ۛR^R?I#%G/Ғ2|,\*Su]|Cv51xi%IIZ߳ld<,*uoz4:'ltG;tK:b=mY $h1bkܜRJ)4ZkDi`xޟ7-<-{zAJǥHn+]? 0{ySXQ2jkħѕjf3IfQeH]Gu<> Z=)ak3+Z*_ޘlN/"I?t?CIwU8񽍦ڽ%"KzH:mZڰ!%)RJi`p.54CG%\|G5\}ǖģէ0wef}+f7mM>#{Z:홙M侵lKJ)R2FKi*:̮IeJzxKҵ=Rj_% ޔtu@RWIgIz/֏ܒt8}I^kEJz,N;XtHI]C,)ұ%+XЊ.{oI:i*;S >uL.ǭRJ)ڮ֚z)Xj*Yc҃q1j'>_ ig33 0;=Z67f= fvVcÀ_㽁ŧM, kVGf+HvԋW^R/3{fvwvT?߄ P7E PP#6@+~\%WAQAAQKEHGJ!!Ǵ?I({d]O/J~p,}u>y^g1I'(cl60[ 0(:+>Fi [P> BS9gtH\- "ʾ|;2SzguBjխmoj-?H灳;"^Ez牙oQw&eܒ'.$-Iia<ِ0P9<>ea[9̆ayHvQ333333- T׻eq<6$Ko c4 "^Om:ʜ'"̔ xQf?2e8;NATD<7NN~|'ߟ 2أz9%i I'JJyS7333~@)"%u@KJ>jV'WH%i#$My#iLkђlmG1ZK$uS*"iELWe|baHIvHE;̦7P-J6tm2à6?>_!DpÊ??t'RIv(Tcג~i?~%LXZi~Bn%IWK@.XhIP="yׄUnI쒇ILk_(A_sN6cLr};ffffsxx cb*a"EWvV%0a>xy,ffff@(-Dz1`ڇ 8$"FDĒYta{J[UY]>X] \XIߟRZՖyaY *y;PQZ(t2ȋx4/ga`9٢5ffffz7;/l}2hL.0ȱ:"bRjҕ{ t$-l !wwaqJ@,uQ|%J0xfU\3)r?WUID$HTvo& ?V}B?"s,@cmISZ|F^%iJ+N&x )c{`s~㟁%e. :VyW"IIK %8%"I:8MISqkwiffff0p-J6t ؉J1.g-j܏RskD\V5(p;p~ ̝g*} %0>A mO7ܰ=""I[3tf|}o;IkoLpYPZ>Qe <T\ޟuI6>O>| ">ʴ](]ogw#|H鎙vdDiFVǁt *kJeSUSoT٤?'fj Uړ\Ks]nAi3333!Lq}iS\<="`Y9%)SCn`l?}#b2*(8P233333kqdfffff@̬ŁY%33333Y>P4\R|;4P53333!h3$t%/i*:lCIKZu?(v_IZZH7z.f@I҇DĄL:x9Z+idt_^tؗ$-^^m ,~$HZJ0O+I wH[bh;ojy #9' KZr̆YKږ) ,$\.6+K:""VI nI+;DĽ6~ ks`CI;Es*(J 6 $j>`௒K:xX3kIoNIcK3S%-lK40K p I \RyC#NIجTel/f?̺(cDLt6֋W[ǴaD<-w/wt5埗u88R>vǁ#bb/offff6(`JX^A@\ $ ,WIi9<{ ^V~z9"wGnt=?qG#F7DĔ1K IB;"n[~'`7aJuy\)._gl66JQ<\C -!em$MLj%-,+iXDLxnDĈ$lAi$˜}x.">@3iZ"ɲj[E}k' | "`QQ]Z3XlgVΡ|OIْtWۄ郇tӻ4!xJ fw|Z5"\-iW}㟾\ܟFeJ B:\KJ:2j8(OttDun~-p.48 p?33333)ҦxzDl:kյ#b*mq= U19ӗt[9_[ Xҕu)^2޵ 4pEk#We)E1-g[Jz+p%ȹ%戸9\ ﺈnw6礪x<#qoʤG}MglW0k|;>"ٜM8LFĸ &Icss1eʁRSIm| flqdfJf֘,%8sFt?ɡ$IZJGm &]Q٬l$%nI5ب/"⡈xC嘜fy.IJ:ֹþKvRIs&Ɏ% -+i(lV5KJqۀ{mHZ]g%ӁSB6Amf<( UYUj7gz6X/uOҚm_` U6%}23,$i9I!`nxT[$m)CuP)ilulMjב%%m-S9 1W{:63333f"&Py`(! YoWg$]id0=RI7SZ&JڇҒ:_YGsLfffffY}!i8HD<90Қ2}/L)3q(P<ٗIs#FU0`qx9棌zDCiL8,bΚ,D~ଙ%̈́-J}3-H2/er'*e"N&Sih;Nj3$3333 @FS v=hs%33333Jffffff-Z(8P233333kqdfffff@̬ŁY%33333Jffffff-Z(8P233333kqdfffff@̬ŁY%33333Jffffff-Z(8P233333kqdfffff@̬ŁY%33333Jffffff-Z(8P233333kqdfffff@̬ŁY%33333Jffffff-Z $}P.xpx.KFo*MGs_ߪ;|۝vIߏ Ρ.(a$mF_ހ} |x)"ʴ__7 g#brE"bwuZ ر xǬ"onoHFYr=ypLD5U{Q7 ӝznx'":GS.^ /u<1X1?~狈})[p2%`XK"n3]'IsQAsT\IL34xL 4EZ @=Tij?ò0g=nﭶ[ҭ$Jq\1/s Ur?#Γ]؈^ǻ#pն]8B2=ow7-Scr'WndQx)g5H$g]Jwml(y^N|Ο. 0T JP) \F B/533Es3vJ huZurISnM֍ߋ2Pn] i^'䩭o!Ij%=!@?":^EEE<%PMʲ.Λ̽[z9y3@3}$zK:\Ҟ̝7%Iy:Iҽn0I_㞒|H.UU%JxҲuE<+H:Sҋ뷩Uy .nOtz8EĺqdD\QX-ѯ):֋4ޜP<'TW,VkeiU:gLۡJ[)v˴sU֪/Vrޔjݫyجʿf/dVU=3U*m|wQΉ6x{={00rm~L?]O1VmvsZ8JWxϟoyo~D`W{dU>~לj?7GAAwP[:f UU{|ump;0WۿWmL_}ϋ5UˁӫW]r&rWeUڣ?}i)7p?RW~`L1'TQPnL_'s|HUaUy.jLo~x.̝ʹG(7\zUK)ߵ p}0|gXyی1Ǵ(Q~ѠDT}ZB9#P ".|١k@f9xfD٬'+:I/Ph ƺx8ߟBCS&\- |ؚrI`o𭈘e W]՟ͺY~x ɟӀ$]E4?ʟP_"@sG~/(oOt*Yo?]rĕ 3Mֈ5(-EPnme7❔qR..-)]1"/nPD?nIH+LL^Q}9Iek72)V)7GPzQz&i9_ʴ\ 82ӿCxr3w+J067t]6"6|&{djK6UD>(}sØbTfh (8!(_-;lJ7ۓ`r&Fw~ϔcQ?q[3]şz}9ú\Fa[`}ݲc;{,(G]שl=LoJ1nmffV9wFyL֞q|D'eJT$;MߞF 'a nj=7srxFtMԾAZ{ "ffӔk{Fij|7E"bJD<IkUSaauwHPYN &g?TnG{ rS}$G2܌>qMRf" J`{B/ )sʬwDP!NGtw+ V;%IfGD˒V|EEe=~{$}"'S~1aR&yxtک}:=|-|l6J|^UBү#e\64OtHR^/|-aJWr(m(̬[NF.uH "hm:=oOr˔G@v%u㋙6#7szTd+ff&)C0n^Hm`]wSYRϦ)7Re-%Jڐrw}`JiDzfqRw9E(ͯo^M Tvt,5qU+K%Biy򇤿- ̀%$'*S=B~L?fyΒtA9%C9 ǀ?|?wH:2 ʸALz]돔 Lqg]!thXAU{)MOH:9?S&hw+eO" ў)7sW_{6PפL6y]tM$53?_1eLr[}zʇ 7HkF.qTDw$kow~+wl;MWOEĆ͋\LEIšG,C?uXr<.ỈA-JV g(NGZ돢k %ZD._Gfݓ)`׈B-"Vf_]mr54/ǎyLkڍ=( of=K6UwfϬ "?*ߥKdg_N(}rtCh"%y*[~Ky4^Ju=ED *?yW7;KP5ך}i 43٘sk3QJ [VlE#VE$DW]cgz/H:Pn6-F/P&%jnUct[_#K1M)-PnKX ʳq xLҟ)($w&k3)l;`uIPB^H;2"U]n^5(.ny~p(cP盹եqJc@=qk;w8zֻeڊ,gͬw7"/ -AxP1YRap-`^L x;ZYEdv:ۯIy7sw~,b6raXߒgoUt`tm3IdM{wW:pJ UYt k܄l7ڜwAwNj4JDUf3=UF69tͬwvX7/ˤ)#|T{vվd+dcZj~\~Nlm~;ؿ;}zݳ) 3I-ش4~?"~C(wn2 %=#ef:0qWO7f ޷OGG{^8&"v@^x8rQ&9n}{"dZ f݇|yWIf~*ebn{.ZQf,yTkfQ@כ|ͬ́Y%33333Jffffff-w2wK:~fG#ffffJK[͌D{Hz+aff-ӃPhfȌJ슘lo`WlfQD v^7Ic1]3w#Jffffff-̬ŁY%33333Jffffff-Z(8P233333kqdfffff@̬ŁYX1 ]VIENDB`dbus-1.10.6/doc/system-activation.txt0000644000175000017500000000611112602773110017525 0ustar00smcvsmcv00000000000000D-BUS System Activation Introduction: The dbus-daemon runs as the dbus user, and is therefore unprivileged. Earlier attempts [1] by David Zeuthen at launching system scripts using a custom DBUS protocol were reviewed, but deemed too difficult to audit, and also due to a multi-threaded design, too difficult to test. In the next few paragraphs I will outline a simpler setuid approach for launching daemons as a configured user. Scope: Launching programs using dbus has been a topic of interest for many months. This would allow simple systems to only start services that are needed, and that are automatically started only when first requested. This removes the need for an init system, and means that we can trivially startup services in parallel. This has immediate pressing need for OLPC, with a longer term evaluation for perhaps Fedora and RHEL. Details: Setuid applications have to used only when absolutely necessary. In this implementation I have an single executable, dbus-daemon-launch-helper, with the ownership root:dbus. This has the permissions 4750, i.e. u+rwx g+rx +setuid. It is located in /usr/libexec/ and thus is not designed to be invoked by a user directly. The helper must not be passed input that can be changed maliciously, and therefore passing a random path with user id is totally out of the question. In this implementation a similar idea as discussed with Davids' patch was taken, that to pass a single name argument to the helper. The service filename of "org.me.test.service" is then searched for in /usr/share/dbus-1/system-services or other specified directories. If applications want to be activated on the system _and_ session busses, then service files should be installed in both directories. A typical service file would look like: [D-BUS Service] Name=org.me.test Exec=/usr/sbin/dbus-test-server.py User=ftp This gives the user to switch to, and also the path of the executable. The service name must match that specified in the /etc/dbus-1/system.d conf file. Precautions taken: * Only the bus name is passed to the helper, and this is validated * We are super paranoid about the user that called us, and what permissions we have. * We clear all environment variables except for DBUS_VERBOSE which is used for debugging * Anything out of the ordinary causes the helper to abort. Launching services: Trivial methods on services can be called directly and the launch helper will start the service and execute the method on the service. The lauching of the service is completely transparent to the caller, e.g.: dbus-send --system --print-reply \ --dest=org.freedesktop.Hal \ /org/freedesktop/Hal/Manager \ org.freedesktop.Hal.Manager.DeviceExists \ string:/org/freedesktop/Hal/devices/computer If you wish to activate the service without calling a well known method, the standard dbus method StartServiceByName can be used: dbus-send --system --print-reply \ --dest=org.freedesktop.DBus \ /org/freedesktop/DBus \ org.freedesktop.DBus.StartServiceByName \ string:org.freedesktop.Hal uint32:0 [1] http://lists.freedesktop.org/archives/dbus/2006-October/006096.html dbus-1.10.6/doc/Makefile.am0000644000175000017500000001117112602773110015337 0ustar00smcvsmcv00000000000000apidir = @htmldir@/api man_pages = \ dbus-cleanup-sockets.1 \ dbus-daemon.1 \ dbus-launch.1 \ dbus-monitor.1 \ dbus-run-session.1 \ dbus-send.1 \ dbus-test-tool.1 \ dbus-update-activation-environment.1 \ dbus-uuidgen.1 \ $(NULL) MAN_XML_FILES = $(patsubst %.1,%.1.xml,$(man_pages)) if DBUS_XML_DOCS_ENABLED man1_MANS = $(man_pages) endif MAN_HTML_FILES = $(patsubst %.1,%.1.html,$(man_pages)) DTDS = \ busconfig.dtd \ introspect.dtd dist_doc_DATA = system-activation.txt # uploaded and distributed, but not installed STATIC_DOCS = \ dbus-faq.xml \ dbus-specification.xml \ dbus-test-plan.xml \ dbus-tutorial.xml \ dbus-api-design.duck \ dcop-howto.txt \ introspect.xsl \ $(DTDS) EXTRA_DIST = \ file-boilerplate.c \ doxygen_to_devhelp.xsl \ $(STATIC_DOCS) html_DATA = dist_html_DATA = # diagram.png/diagram.svg aren't really HTML, but must go in the same # directory as the HTML to avoid broken links STATIC_HTML = \ diagram.png \ diagram.svg \ $(NULL) # Static HTML helper files generated by yelp-build. YELP_STATIC_HTML = \ yelp.js \ C.css \ jquery.js \ jquery.syntax.js \ jquery.syntax.brush.html.js \ jquery.syntax.core.js \ jquery.syntax.layout.yelp.js \ $(NULL) dist_html_DATA += $(STATIC_HTML) # Content HTML files generated by yelp-build. YELP_HTML = \ dbus-api-design.html \ $(NULL) XMLTO_HTML = \ dbus-faq.html \ dbus-specification.html \ dbus-test-plan.html \ dbus-tutorial.html \ $(MAN_HTML_FILES) \ $(NULL) if DBUS_XML_DOCS_ENABLED html_DATA += $(XMLTO_HTML) %.html: %.xml $(XMLTO) html-nochunks $< %.1: %.1.xml $(XMLTO) man $< endif if DBUS_DOXYGEN_DOCS_ENABLED all-local:: doxygen.stamp doxygen.stamp: $(wildcard $(top_srcdir)/dbus/*.[ch]) $(AM_V_GEN)cd $(top_builddir) && doxygen Doxyfile @touch $@ if DBUS_HAVE_XSLTPROC html_DATA += dbus.devhelp dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp $(XSLTPROC) -o $@ $< api/xml/index.xml endif if DBUS_DUCKTYPE_DOCS_ENABLED html_DATA += $(YELP_HTML) $(YELP_STATIC_HTML) %.page: %.duck $(DUCKTYPE) -o $@ $< %.html: %.page $(YELP_BUILD) html $< $(YELP_STATIC_HTML): $(YELP_HTML) endif # this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile # (which it isn't currently) install-data-local:: doxygen.stamp $(MKDIR_P) $(DESTDIR)$(apidir) $(INSTALL_DATA) api/html/* $(DESTDIR)$(apidir) uninstall-local:: rm -f $(DESTDIR)$(apidir)/*.html rm -f $(DESTDIR)$(apidir)/*.png rm -f $(DESTDIR)$(apidir)/*.css rm -f $(DESTDIR)$(apidir)/*.js rm -f $(DESTDIR)$(htmldir)/*.html rm -f $(DESTDIR)$(docdir)/*.txt rm -f $(DESTDIR)$(htmldir)/*.png rm -f $(DESTDIR)$(htmldir)/*.svg rmdir --ignore-fail-on-non-empty $(DESTDIR)$(apidir) || \ rmdir $(DESTDIR)$(apidir) endif if DBUS_CAN_UPLOAD_DOCS BONUS_FILES = \ $(top_srcdir)/README \ $(top_srcdir)/HACKING \ $(top_srcdir)/AUTHORS \ $(top_srcdir)/NEWS \ $(top_srcdir)/COPYING \ $(top_srcdir)/ChangeLog dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML) $(AM_V_at)rm -rf $@ $@.tmp $(AM_V_GEN)$(MKDIR_P) $@.tmp/api $(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp $(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp $(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp $(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp $(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp $(AM_V_at)cp -r api/html @abs_builddir@/$@.tmp/api $(AM_V_at)mv $@.tmp $@ dbus-docs.tar.gz: dbus-docs $(AM_V_GEN)tar czf $@ $< DOC_SERVER = dbus.freedesktop.org DOC_WWW_DIR = /srv/dbus.freedesktop.org/www SPECIFICATION_SERVER = specifications.freedesktop.org SPECIFICATION_PATH = /srv/specifications.freedesktop.org/www/dbus/1.0 maintainer-upload-docs: dbus-docs.tar.gz dbus-docs scp dbus-docs.tar.gz $(DOC_SERVER):$(DOC_WWW_DIR)/ rsync -rpvzP --chmod=Dg+s,ug+rwX,o=rX \ dbus-docs/ $(DOC_SERVER):$(DOC_WWW_DIR)/doc/ cd $(srcdir) && scp -p $(DTDS) $(SPECIFICATION_SERVER):$(SPECIFICATION_PATH)/ else maintainer-upload-docs: @echo "Can't upload documentation! Re-run configure with" @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs" @echo "and ensure that man2html is installed." @false endif CLEANFILES = \ $(man1_MANS) \ $(MAN_XML_FILES) \ $(XMLTO_HTML) \ $(YELP_HTML) \ $(YELP_STATIC_HTML) \ $(NULL) clean-local: rm -f $(html_DATA) rm -rf api rm -rf dbus-docs dbus-docs.tmp rm -f *.1.html rm -f doxygen.stamp dbus-1.10.6/test/0000755000175000017500000000000012627367774013542 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/dbus-test-runner0000755000175000017500000000124412602773110016664 0ustar00smcvsmcv00000000000000#!/bin/sh set -e dir="$1" shift if ! test -d "$dir"; then echo "Usage: dbus-test-runner directory [executable...]" exit 0 fi passed=0 failed=0 skipped=0 for prog in "$@"; do e=0 "$dir/$prog" || e=$? case $e in (0) echo "PASS: $prog" passed=`expr $passed + 1` ;; (77) echo "SKIP: $prog" skipped=`expr $skipped + 1` ;; (*) echo "FAIL: $prog" failed=`expr $failed + 1` ;; esac done if test $failed = 0; then # avoid saying "FAIL", to make it easy to grep results! echo "PASSED $passed / SKIPPED $skipped" exit 0 else echo "PASSED $passed / FAILED $failed / SKIPPED $skipped" exit 1 fi dbus-1.10.6/test/tap-test.sh.in0000644000175000017500000000113712602773110016220 0ustar00smcvsmcv00000000000000#!/bin/sh # Wrapper to make an Automake-style test output TAP syntax: # # - arbitrary stdout/stderr is sent to stderr where it will not be # interpreted as TAP # - it is treated as a single test-case # - exit 77 is a skip # - exit 0 is a pass # - anything else is a failure # # Usage: use sed to replace @RUN@ with the shell command-line to be run. set -e # we plan to do 1 test-case echo "1..1" e=0 @RUN@ >&2 || e=$? case "$e" in (0) echo "ok 1 @RUN@" ;; (77) echo "ok 1 # SKIP @RUN@" ;; (*) echo "not ok 1 @RUN@ (exit status $e)" ;; esac dbus-1.10.6/test/glib-tap-test.sh0000755000175000017500000000160512622707003016531 0ustar00smcvsmcv00000000000000#!/bin/sh # Wrapper to make GTest tests output TAP syntax, because Automake's test # drivers do not currently support passing the same command-line argument # to each test executable. All GTest tests produce TAP output if invoked # with the --tap option. # # Usage: "glib-tap-test.sh test-foo --verbose ..." is equivalent to # "test-foo --tap --verbose ..." set -e t="$1" shift case "$t" in (*.exe) # We're running a Windows executable, possibly on a Unix # platform. Avoid having invalid TAP syntax like "ok 3\r\n" # where "ok 3\n" was intended. echo 1 > "$t".exit-status.tmp ( set +e "$t" --tap "$@" echo "$?" > "$t".exit-status.tmp ) | sed -e 's/\r$//' e="$(cat "$t".exit-status.tmp)" rm "$t".exit-status.tmp exit "$e" ;; (*) exec "$t" --tap "$@" ;; esac dbus-1.10.6/test/uid-permissions.c0000644000175000017500000001663112624704607017032 0ustar00smcvsmcv00000000000000/* Integration tests for the dbus-daemon's uid-based hardening * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * Copyright © 2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "test-utils-glib.h" typedef struct { gboolean skip; TestMainContext *ctx; DBusError e; GError *ge; GPid daemon_pid; DBusConnection *conn; } Fixture; typedef struct { const char *config_file; TestUser user; gboolean expect_success; } Config; static void setup (Fixture *f, gconstpointer context) { const Config *config = context; gchar *address; f->ctx = test_main_context_get (); f->ge = NULL; dbus_error_init (&f->e); address = test_get_dbus_daemon (config ? config->config_file : NULL, TEST_USER_MESSAGEBUS, &f->daemon_pid); if (address == NULL) { f->skip = TRUE; return; } f->conn = test_connect_to_bus_as_user (f->ctx, address, config ? config->user : TEST_USER_ME); if (f->conn == NULL) f->skip = TRUE; g_free (address); } static void test_uae (Fixture *f, gconstpointer context) { const Config *config = context; DBusMessage *m; DBusPendingCall *pc; DBusMessageIter args_iter; DBusMessageIter arr_iter; if (f->skip) return; m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); /* Append an empty a{ss} (string => string dictionary). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "{ss}", &arr_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); if (config->expect_success) { /* it succeeds */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_METHOD_RETURN); } else { /* it fails, yielding an error message with one string argument */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR); g_assert_cmpstr (dbus_message_get_error_name (m), ==, DBUS_ERROR_ACCESS_DENIED); g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); } dbus_message_unref (m); } static void test_monitor (Fixture *f, gconstpointer context) { const Config *config = context; DBusMessage *m; DBusPendingCall *pc; DBusMessageIter args_iter; DBusMessageIter arr_iter; dbus_uint32_t no_flags = 0; if (f->skip) return; m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); /* Append an empty as (string array). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "s", &arr_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter) || !dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_UINT32, &no_flags)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); if (config->expect_success) { /* it succeeds */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_METHOD_RETURN); } else { /* it fails, yielding an error message with one string argument */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR); g_assert_cmpstr (dbus_message_get_error_name (m), ==, DBUS_ERROR_ACCESS_DENIED); g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); } dbus_message_unref (m); } static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { dbus_error_free (&f->e); g_clear_error (&f->ge); if (f->conn != NULL) { dbus_connection_close (f->conn); dbus_connection_unref (f->conn); f->conn = NULL; } if (f->daemon_pid != 0) { test_kill_pid (f->daemon_pid); g_spawn_close_pid (f->daemon_pid); f->daemon_pid = 0; } test_main_context_unref (f->ctx); } static Config root_ok_config = { "valid-config-files/multi-user.conf", TEST_USER_ROOT, TRUE }; static Config messagebus_ok_config = { "valid-config-files/multi-user.conf", TEST_USER_MESSAGEBUS, TRUE }; static Config other_fail_config = { "valid-config-files/multi-user.conf", TEST_USER_OTHER, FALSE }; int main (int argc, char **argv) { test_init (&argc, &argv); /* UpdateActivationEnvironment used to be allowed by dbus-daemon for root * and messagebus but not for other users (although system.conf forbids it * for everyone, and it's useless). It is now hard-coded to fail on a * system bus for everyone, so don't assert that root and messagebus * may call it; continue to assert that it is denied for unprivileged * users though. */ g_test_add ("/uid-permissions/uae/other", Fixture, &other_fail_config, setup, test_uae, teardown); /* BecomeMonitor has the behaviour that UAE used to have. */ g_test_add ("/uid-permissions/monitor/root", Fixture, &root_ok_config, setup, test_monitor, teardown); g_test_add ("/uid-permissions/monitor/messagebus", Fixture, &messagebus_ok_config, setup, test_monitor, teardown); g_test_add ("/uid-permissions/monitor/other", Fixture, &other_fail_config, setup, test_monitor, teardown); return g_test_run (); } dbus-1.10.6/test/syntax.c0000644000175000017500000001546612602773110015222 0ustar00smcvsmcv00000000000000/* Simple sanity-check for D-Bus syntax validation. * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "test-utils-glib.h" typedef struct { DBusError e; } Fixture; typedef struct { dbus_bool_t (*function) (const char *, DBusError *); const char * const * valid; const char * const * invalid; } Test; Test paths, interfaces, members, errors, bus_names, signatures, single_signatures, strings; const char * const valid_paths[] = { "/", "/a", "/_", "/a/b/c", "/com/example/123", "/org/freedesktop/DBus", "/org/freedesktop/Telepathy/AccountManager", NULL }; const char * const invalid_paths[] = { "", ".", "//", "/a/", "/-", "/com//example/MyApp", "/$", "/\xa9", /* © in latin-1 */ "/\xc2\xa9", /* © in UTF-8 */ NULL }; const char * const valid_interfaces[] = { "com.example", "com.example.a0", "org.freedesktop.DBus", NULL }; const char * const invalid_interfaces[] = { "", "com", "com.example.", "com.example..a0", "com.example.0a", "com.example.a$", "com.example.a\xa9", "com.example.a\xc2\xa9", NULL }; const char * const valid_members[] = { "_", "a", "a0", "GetAll", "BadgerMushroomSnake", NULL }; const char * const invalid_members[] = { "", "-", "a-", "0", "0_", "Badger.Mushroom", "a$", "a\xa9", "a\xc2\xa9", NULL }; const char * const valid_errors[] = { "com.example", "com.example.a0", "org.freedesktop.DBus.NameHasNoOwner", NULL }; const char * const invalid_errors[] = { "", "com", "com.example.", "com.example..a0", "com.example.0a", "com.example.a$", "com.example.a\xa9", "com.example.a\xc2\xa9", NULL }; const char * const valid_bus_names[] = { "com.example", "com.example.a0", "com.example._", ":1.42", ":1.2.3.4.5", ":com.example", "org.freedesktop.DBus", NULL }; const char * const invalid_bus_names[] = { "", "com", "com.example.", "com.example..a0", "com.example.0a", "com.example.a:b", "com.example.a\xa9", "com.example.a\xc2\xa9", NULL }; const char * const valid_signatures[] = { "", "a{sv}", NULL }; const char * const invalid_signatures[] = { "a", "a{s_}", NULL }; const char * const valid_single_signatures[] = { "s", "a{sv}", NULL }; const char * const invalid_single_signatures[] = { "", "a", "sv", "a{sv}as", NULL }; const char * const valid_strings[] = { "", "\xc2\xa9", /* UTF-8 (c) symbol */ "\xef\xbf\xbe", /* U+FFFE is reserved but Corrigendum 9 says it's OK */ NULL }; const char * const invalid_strings[] = { "\xa9", /* Latin-1 (c) symbol */ "\xed\xa0\x80", /* UTF-16 surrogates are not valid in UTF-8 */ NULL }; static void setup (Fixture *f, gconstpointer arg G_GNUC_UNUSED) { dbus_error_init (&f->e); #define FILL_TEST(name, func) \ do { \ (name).function = (func); \ (name).valid = valid_ ## name; \ (name).invalid = invalid_ ## name; \ } while (0) FILL_TEST (paths, dbus_validate_path); FILL_TEST (interfaces, dbus_validate_interface); FILL_TEST (members, dbus_validate_member); FILL_TEST (errors, dbus_validate_error_name); FILL_TEST (bus_names, dbus_validate_bus_name); FILL_TEST (signatures, dbus_signature_validate); FILL_TEST (single_signatures, dbus_signature_validate_single); FILL_TEST (strings, dbus_validate_utf8); } static void test_syntax (Fixture *f, gconstpointer arg) { const Test *test = arg; int i; g_assert (test != NULL); g_assert (test->function != NULL); g_assert (test->valid != NULL); g_assert (test->invalid != NULL); for (i = 0; test->valid[i] != NULL; i++) { dbus_bool_t ok = test->function (test->valid[i], &f->e); if (dbus_error_is_set (&f->e)) g_error ("%s was considered invalid: %s: %s", test->valid[i], f->e.name, f->e.message); if (!ok) g_error ("%s was considered invalid without an error", test->valid[i]); } for (i = 0; test->invalid[i] != NULL; i++) { dbus_bool_t ok = test->function (test->invalid[i], &f->e); if (ok) g_error ("%s should have been considered invalid", test->invalid[i]); if (!dbus_error_is_set (&f->e)) g_error ("%s should have an error set", test->invalid[i]); if (!dbus_validate_error_name (f->e.name, NULL)) g_error ("%s produced an invalid error name: %s", test->invalid[i], f->e.name); if (!dbus_validate_utf8 (f->e.message, NULL)) g_error ("%s produced an invalid error message: %s", test->invalid[i], f->e.message); dbus_error_free (&f->e); } } static void teardown (Fixture *f, gconstpointer arg G_GNUC_UNUSED) { dbus_error_free (&f->e); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/syntax/path", Fixture, &paths, setup, test_syntax, teardown); g_test_add ("/syntax/interface", Fixture, &interfaces, setup, test_syntax, teardown); g_test_add ("/syntax/error", Fixture, &errors, setup, test_syntax, teardown); g_test_add ("/syntax/member", Fixture, &members, setup, test_syntax, teardown); g_test_add ("/syntax/bus-name", Fixture, &bus_names, setup, test_syntax, teardown); g_test_add ("/syntax/signature", Fixture, &signatures, setup, test_syntax, teardown); g_test_add ("/syntax/single-signature", Fixture, &single_signatures, setup, test_syntax, teardown); g_test_add ("/syntax/utf8", Fixture, &strings, setup, test_syntax, teardown); return g_test_run (); } dbus-1.10.6/test/spawn-test.c0000644000175000017500000000142712602773110015771 0ustar00smcvsmcv00000000000000#include #include #include #include #include static void setup_func (void *data) { printf ("entering setup func.\n"); } int main (int argc, char **argv) { char **argv_copy; int i; DBusError error; if (argc < 2) { fprintf (stderr, "You need to specify a program to launch.\n"); return -1; } argv_copy = dbus_new (char *, argc); for (i = 0; i < argc - 1; i++) argv_copy [i] = argv[i + 1]; argv_copy[argc - 1] = NULL; if (!_dbus_spawn_async_with_babysitter (NULL, argv_copy[0], argv_copy, NULL, setup_func, NULL, &error)) { fprintf (stderr, "Could not launch application: \"%s\"\n", error.message); } dbus_free(argv_copy); return 0; } dbus-1.10.6/test/test-sleep-forever.c0000644000175000017500000000044712602773110017420 0ustar00smcvsmcv00000000000000/* This is a process that just sleeps infinitely. */ #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef DBUS_WIN # include # define sleep Sleep #endif int main (int argc, char **argv) { while (1) sleep (10000000); return 1; } dbus-1.10.6/test/test-shell-service.c0000644000175000017500000001155612602773110017412 0ustar00smcvsmcv00000000000000#include #include "test-utils.h" static DBusLoop *loop; static dbus_bool_t already_quit = FALSE; static const char* echo_path = "/org/freedesktop/TestSuite"; typedef struct { int argc; char **argv; } EchoData; static void quit (void) { if (!already_quit) { _dbus_loop_quit (loop); already_quit = TRUE; } } static void die (const char *message) { fprintf (stderr, "*** test-service: %s", message); exit (1); } static DBusHandlerResult handle_echo (DBusConnection *connection, DBusMessage *message) { DBusError error; DBusMessage *reply; DBusMessageIter iter; int i; EchoData *d; _dbus_verbose ("sending reply to Echo method\n"); if (!dbus_connection_get_object_path_data (connection, echo_path, (void **)&d)) die ("No memory"); dbus_error_init (&error); reply = dbus_message_new_method_return (message); if (reply == NULL) die ("No memory\n"); dbus_message_iter_init_append (reply, &iter); for (i = 0; i < d->argc; ++i) if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &(d->argv[i]))) die ("No memory\n"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); fprintf (stderr, "Shell echo service echoed the command line\n"); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static void path_unregistered_func (DBusConnection *connection, void *user_data) { /* connection was finalized */ } static DBusHandlerResult path_message_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "Echo")) return handle_echo (connection, message); else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "Exit")) { quit (); return DBUS_HANDLER_RESULT_HANDLED; } else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusObjectPathVTable echo_vtable = { path_unregistered_func, path_message_func, NULL, }; static DBusHandlerResult filter_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { quit (); return DBUS_HANDLER_RESULT_HANDLED; } else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } int main (int argc, char **argv) { DBusConnection *connection; DBusError error; EchoData echo_data; int result; echo_data.argc = argc; echo_data.argv = argv; dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_STARTER, &error); if (connection == NULL) { fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", error.message); dbus_error_free (&error); return 1; } loop = _dbus_loop_new (); if (loop == NULL) die ("No memory\n"); if (!test_connection_setup (loop, connection)) die ("No memory\n"); if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) die ("No memory"); if (!dbus_connection_register_object_path (connection, echo_path, &echo_vtable, (void*) &echo_data)) die ("No memory"); { void *d; if (!dbus_connection_get_object_path_data (connection, echo_path, &d)) die ("No memory"); if (d != (void*) &echo_data) die ("dbus_connection_get_object_path_data() doesn't seem to work right\n"); } result = dbus_bus_request_name (connection, "org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess", 0, &error); if (dbus_error_is_set (&error)) { fprintf (stderr, "Error %s\n", error.message); _dbus_verbose ("*** Failed to acquire service: %s\n", error.message); dbus_error_free (&error); exit (1); } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { fprintf (stderr, "Unable to acquire service: code %d\n", result); _dbus_verbose ("*** Failed to acquire service: %d\n", result); exit (1); } _dbus_verbose ("*** Test service entering main loop\n"); _dbus_loop_run (loop); test_connection_shutdown (loop, connection); dbus_connection_remove_filter (connection, filter_func, NULL); dbus_connection_unref (connection); _dbus_loop_unref (loop); loop = NULL; dbus_shutdown (); _dbus_verbose ("*** Test service exiting\n"); return 0; } dbus-1.10.6/test/shell-test.c0000644000175000017500000001112112624705346015752 0ustar00smcvsmcv00000000000000#include #include #include #include #include #include #include #include #include static int test_num = 0; static int num_failed = 0; static dbus_bool_t test_command_line_internal (dbus_bool_t should_work, const char *arg1, va_list var_args) { int i, original_argc, shell_argc; char **shell_argv; char **original_argv; char *command_line, *tmp; DBusString str; DBusList *list = NULL, *node; DBusError error; _dbus_list_append (&list, (char *)arg1); do { tmp = va_arg (var_args, char *); if (!tmp) break; _dbus_list_append (&list, tmp); } while (tmp); original_argc = _dbus_list_get_length (&list); original_argv = dbus_new (char *, original_argc); _dbus_string_init (&str); for (i = 0, node = _dbus_list_get_first_link (&list); i < original_argc && node; i++, node = _dbus_list_get_next_link (&list, node)) { original_argv[i] = node->data; if (i > 0) _dbus_string_append_byte (&str, ' '); _dbus_string_append (&str, original_argv[i]); } _dbus_list_clear (&list); command_line = _dbus_string_get_data (&str); printf ("# Testing command line '%s'\n", command_line); dbus_error_init (&error); if (!_dbus_shell_parse_argv (command_line, &shell_argc, &shell_argv, &error)) { printf ("# Error%s parsing command line: %s\n", should_work ? "" : " (as expected)", error.message ? error.message : ""); dbus_free (original_argv); return !should_work; } else { if (shell_argc != original_argc) { printf ("# Number of arguments returned (%d) don't match original (%d)\n", shell_argc, original_argc); dbus_free (original_argv); dbus_free_string_array (shell_argv); return FALSE; } printf ("# Number of arguments: %d\n", shell_argc); for (i = 0; i < shell_argc; i++) { char *unquoted; unquoted = _dbus_shell_unquote (original_argv[i]); if (strcmp (unquoted ? unquoted : "", shell_argv[i] ? shell_argv[i] : "")) { printf ("Position %d, returned argument (%s) does not match original (%s)\n", i, shell_argv[i], unquoted); dbus_free (unquoted); dbus_free (original_argv); dbus_free_string_array (shell_argv); return FALSE; } dbus_free (unquoted); if (shell_argv[i]) printf ("Argument %d = %s\n", i, shell_argv[i]); } dbus_free_string_array (shell_argv); } _dbus_string_free (&str); dbus_free (original_argv); if (!should_work) { printf ("# Expected an error\n"); return FALSE; } return TRUE; } static void test_command_line (const char *arg1, ...) { va_list var_args; va_start (var_args, arg1); if (test_command_line_internal (TRUE, arg1, var_args)) { printf ("ok %d\n", ++test_num); } else { printf ("not ok %d\n", ++test_num); num_failed++; } va_end (var_args); } static void test_command_line_fails (const char *arg1, ...) { va_list var_args; va_start (var_args, arg1); if (test_command_line_internal (FALSE, arg1, var_args)) { printf ("ok %d\n", ++test_num); } else { printf ("not ok %d\n", ++test_num); num_failed++; } va_end (var_args); } /* This test outputs TAP syntax: http://testanything.org/ */ int main (int argc, char **argv) { test_command_line ("command", "-s", "--force-shutdown", "\"a string\"", "123", NULL); test_command_line ("command", "-s", NULL); test_command_line ("/opt/gnome/bin/service-start", NULL); test_command_line ("grep", "-l", "-r", "-i", "'whatever'", "files*.c", NULL); test_command_line ("/home/boston/johnp/devel-local/dbus/test/test-segfault", NULL); test_command_line ("ls", "-l", "-a", "--colors", _dbus_get_tmpdir(), NULL); test_command_line ("rsync-to-server", NULL); test_command_line ("test-segfault", "--no-segfault", NULL); test_command_line ("evolution", "mailto:pepe@cuco.com", NULL); test_command_line ("run", "\"a \n multiline\"", NULL); test_command_line_fails ("ls", "\"a wrong string'", NULL); /* Tell the TAP driver that we have done all the tests we plan to do. * This is how it can distinguish between an unexpected exit and * successful completion. */ printf ("1..%d\n", test_num); return (num_failed != 0); } dbus-1.10.6/test/test-service.c0000644000175000017500000003264612602773110016310 0ustar00smcvsmcv00000000000000#include #include "test-utils.h" #ifdef HAVE_UNISTD_H #include #endif static DBusLoop *loop; static dbus_bool_t already_quit = FALSE; static dbus_bool_t hello_from_self_reply_received = FALSE; static void quit (void) { if (!already_quit) { _dbus_loop_quit (loop); already_quit = TRUE; } } static void die (const char *message) { fprintf (stderr, "*** test-service: %s", message); exit (1); } static void check_hello_from_self_reply (DBusPendingCall *pcall, void *user_data) { DBusMessage *reply; DBusMessage *echo_message, *echo_reply = NULL; DBusError error; DBusConnection *connection; int type; dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_STARTER, &error); if (connection == NULL) { fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", error.message); dbus_error_free (&error); die("no memory"); } echo_message = (DBusMessage *)user_data; reply = dbus_pending_call_steal_reply (pcall); type = dbus_message_get_type (reply); if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN) { const char *s; printf ("Reply from HelloFromSelf received\n"); if (!dbus_message_get_args (echo_message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) { echo_reply = dbus_message_new_error (echo_message, error.name, error.message); if (echo_reply == NULL) die ("No memory\n"); } else { echo_reply = dbus_message_new_method_return (echo_message); if (echo_reply == NULL) die ("No memory\n"); if (!dbus_message_append_args (echo_reply, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) die ("No memory"); } if (!dbus_connection_send (connection, echo_reply, NULL)) die ("No memory\n"); dbus_message_unref (echo_reply); } else if (type == DBUS_MESSAGE_TYPE_ERROR) { dbus_set_error_from_message (&error, reply); printf ("Error type in reply: %s\n", error.message); if (strcmp (error.name, DBUS_ERROR_NO_MEMORY) != 0) { echo_reply = dbus_message_new_error (echo_reply, error.name, error.message); if (echo_reply == NULL) die ("No memory\n"); if (!dbus_connection_send (connection, echo_reply, NULL)) die ("No memory\n"); dbus_message_unref (echo_reply); } dbus_error_free (&error); } else _dbus_assert_not_reached ("Unexpected message received\n"); hello_from_self_reply_received = TRUE; dbus_message_unref (reply); dbus_message_unref (echo_message); dbus_pending_call_unref (pcall); dbus_connection_unref (connection); } static DBusHandlerResult handle_run_hello_from_self (DBusConnection *connection, DBusMessage *message) { DBusError error; DBusMessage *reply, *self_message; DBusPendingCall *pcall; char *s; _dbus_verbose ("sending reply to Echo method\n"); dbus_error_init (&error); if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) { reply = dbus_message_new_error (message, error.name, error.message); if (reply == NULL) die ("No memory\n"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } printf ("Sending HelloFromSelf\n"); _dbus_verbose ("*** Sending message to self\n"); self_message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "HelloFromSelf"); if (self_message == NULL) die ("No memory"); if (!dbus_connection_send_with_reply (connection, self_message, &pcall, -1)) die("No memory"); dbus_message_ref (message); if (!dbus_pending_call_set_notify (pcall, check_hello_from_self_reply, (void *)message, NULL)) die("No memory"); printf ("Sent HelloFromSelf\n"); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult handle_echo (DBusConnection *connection, DBusMessage *message) { DBusError error; DBusMessage *reply; char *s; _dbus_verbose ("sending reply to Echo method\n"); dbus_error_init (&error); if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) { reply = dbus_message_new_error (message, error.name, error.message); if (reply == NULL) die ("No memory\n"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } reply = dbus_message_new_method_return (message); if (reply == NULL) die ("No memory\n"); if (!dbus_message_append_args (reply, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) die ("No memory"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); fprintf (stderr, "Echo service echoed string: \"%s\"\n", s); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult handle_delay_echo (DBusConnection *connection, DBusMessage *message) { DBusError error; DBusMessage *reply; char *s; _dbus_verbose ("sleeping for a short time\n"); _dbus_sleep_milliseconds (50); _dbus_verbose ("sending reply to DelayEcho method\n"); dbus_error_init (&error); if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) { reply = dbus_message_new_error (message, error.name, error.message); if (reply == NULL) die ("No memory\n"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } reply = dbus_message_new_method_return (message); if (reply == NULL) die ("No memory\n"); if (!dbus_message_append_args (reply, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) die ("No memory"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory\n"); fprintf (stderr, "DelayEcho service echoed string: \"%s\"\n", s); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static void path_unregistered_func (DBusConnection *connection, void *user_data) { /* connection was finalized */ } static DBusHandlerResult path_message_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "Echo")) return handle_echo (connection, message); else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "DelayEcho")) return handle_delay_echo (connection, message); else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "Exit")) { quit (); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "EmitFoo")) { /* Emit the Foo signal */ DBusMessage *signal; double v_DOUBLE; _dbus_verbose ("emitting signal Foo\n"); signal = dbus_message_new_signal ("/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Foo"); if (signal == NULL) die ("No memory\n"); v_DOUBLE = 42.6; if (!dbus_message_append_args (signal, DBUS_TYPE_DOUBLE, &v_DOUBLE, DBUS_TYPE_INVALID)) die ("No memory"); if (!dbus_connection_send (connection, signal, NULL)) die ("No memory\n"); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "RunHelloFromSelf")) { return handle_run_hello_from_self (connection, message); } else if (dbus_message_is_method_call (message, "org.freedesktop.TestSuite", "HelloFromSelf")) { DBusMessage *reply; printf ("Received the HelloFromSelf message\n"); reply = dbus_message_new_method_return (message); if (reply == NULL) die ("No memory"); if (!dbus_connection_send (connection, reply, NULL)) die ("No memory"); return DBUS_HANDLER_RESULT_HANDLED; } else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusObjectPathVTable echo_vtable = { path_unregistered_func, path_message_func, NULL, }; static const char* echo_path = "/org/freedesktop/TestSuite" ; static DBusHandlerResult filter_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { quit (); return DBUS_HANDLER_RESULT_HANDLED; } else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } int main (int argc, char **argv) { DBusError error; int result; DBusConnection *connection; const char *name; #ifndef DBUS_WIN dbus_bool_t do_fork = FALSE; #endif if (argc != 3) { name = "org.freedesktop.DBus.TestSuiteEchoService"; } else { name = argv[1]; #ifndef DBUS_WIN do_fork = strcmp (argv[2], "fork") == 0; #endif } /* The bare minimum for simulating a program "daemonizing"; the intent * is to test services which move from being legacy init scripts to * activated services. * https://bugzilla.redhat.com/show_bug.cgi?id=545267 */ #ifndef DBUS_WIN if (do_fork) { pid_t pid = fork (); if (pid != 0) exit (0); sleep (1); } #endif dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_STARTER, &error); if (connection == NULL) { fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", error.message); dbus_error_free (&error); return 1; } loop = _dbus_loop_new (); if (loop == NULL) die ("No memory\n"); if (!test_connection_setup (loop, connection)) die ("No memory\n"); if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) die ("No memory"); if (!dbus_connection_register_object_path (connection, echo_path, &echo_vtable, (void*) 0xdeadbeef)) die ("No memory"); { void *d; if (!dbus_connection_get_object_path_data (connection, echo_path, &d)) die ("No memory"); if (d != (void*) 0xdeadbeef) die ("dbus_connection_get_object_path_data() doesn't seem to work right\n"); } result = dbus_bus_request_name (connection, name, 0, &error); if (dbus_error_is_set (&error)) { fprintf (stderr, "Error %s\n", error.message); _dbus_verbose ("*** Failed to acquire service: %s\n", error.message); dbus_error_free (&error); exit (1); } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { fprintf (stderr, "Unable to acquire service: code %d\n", result); _dbus_verbose ("*** Failed to acquire service: %d\n", result); exit (1); } _dbus_verbose ("*** Test service entering main loop\n"); _dbus_loop_run (loop); test_connection_shutdown (loop, connection); dbus_connection_remove_filter (connection, filter_func, NULL); dbus_connection_unref (connection); _dbus_loop_unref (loop); loop = NULL; dbus_shutdown (); _dbus_verbose ("*** Test service exiting\n"); return 0; } dbus-1.10.6/test/test-segfault.c0000644000175000017500000000170412602773110016451 0ustar00smcvsmcv00000000000000/* This is simply a process that segfaults */ #include #include #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_SETRLIMIT #include #endif #ifdef HAVE_SYS_PRCTL_H #include #endif int main (int argc, char **argv) { char *p; #if HAVE_SETRLIMIT /* No core dumps please, we know we crashed. */ struct rlimit r = { 0, }; getrlimit (RLIMIT_CORE, &r); r.rlim_cur = 0; setrlimit (RLIMIT_CORE, &r); #endif #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) /* Really, no core dumps please. On Linux, if core_pattern is * set to a pipe (for abrt/apport/corekeeper/etc.), RLIMIT_CORE of 0 * is ignored (deliberately, so people can debug init(8) and other * early stuff); but Linux has PR_SET_DUMPABLE, so we can avoid core * dumps anyway. */ prctl (PR_SET_DUMPABLE, 0, 0, 0, 0); #endif #ifdef HAVE_RAISE raise (SIGSEGV); #endif p = NULL; *p = 'a'; return 0; } dbus-1.10.6/test/sd-activation.c0000644000175000017500000004443312624704607016446 0ustar00smcvsmcv00000000000000/* Unit tests for systemd activation. * * Copyright © 2010-2011 Nokia Corporation * Copyright © 2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "test-utils-glib.h" typedef struct { TestMainContext *ctx; DBusError e; GError *ge; gchar *address; GPid daemon_pid; DBusConnection *caller; const char *caller_name; DBusConnection *systemd; const char *systemd_name; DBusMessage *systemd_message; DBusConnection *activated; const char *activated_name; DBusMessage *activated_message; } Fixture; /* this is a macro so it gets the right line number */ #define assert_signal(m, \ sender, path, iface, member, signature, \ destination) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \ g_assert_cmpstr (dbus_message_get_member (m), ==, member); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ } while (0) #define assert_method_call(m, sender, \ destination, path, iface, method, signature) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \ g_assert_cmpstr (dbus_message_get_member (m), ==, method); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ } while (0) #define assert_method_reply(m, sender, destination, signature) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \ } while (0) static DBusHandlerResult systemd_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired") || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameLost")) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } g_test_message("sender %s iface %s member %s", dbus_message_get_sender (message), dbus_message_get_interface (message), dbus_message_get_member (message)); g_assert (f->systemd_message == NULL); f->systemd_message = dbus_message_ref (message); if (dbus_message_is_method_call (message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { g_assert (dbus_message_get_no_reply (message)); g_test_message("got call"); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult activated_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired") || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameLost")) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } g_assert (f->activated_message == NULL); f->activated_message = dbus_message_ref (message); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void setup (Fixture *f, gconstpointer context G_GNUC_UNUSED) { f->ctx = test_main_context_get (); f->ge = NULL; dbus_error_init (&f->e); f->address = test_get_dbus_daemon ( "valid-config-files/systemd-activation.conf", TEST_USER_ME, &f->daemon_pid); if (f->address == NULL) return; f->caller = test_connect_to_bus (f->ctx, f->address); f->caller_name = dbus_bus_get_unique_name (f->caller); } static void take_well_known_name (Fixture *f, DBusConnection *connection, const char *name) { int ret; ret = dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); } static void test_activation (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; /* The sender sends a message to an activatable service. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1")) g_error ("OOM"); dbus_connection_send (f->caller, m, NULL); dbus_message_unref (m); /* The fake systemd connects to the bus. */ f->systemd = test_connect_to_bus (f->ctx, f->address); if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL)) g_error ("OOM"); f->systemd_name = dbus_bus_get_unique_name (f->systemd); take_well_known_name (f, f->systemd, "org.freedesktop.systemd1"); /* It gets its activation request. */ while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* systemd starts the activatable service. */ f->activated = test_connect_to_bus (f->ctx, f->address); if (!dbus_connection_add_filter (f->activated, activated_filter, f, NULL)) g_error ("OOM"); f->activated_name = dbus_bus_get_unique_name (f->activated); take_well_known_name (f, f->activated, "com.example.SystemdActivatable1"); /* The message is delivered to the activatable service. */ while (f->activated_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->activated_message; f->activated_message = NULL; assert_signal (m, f->caller_name, "/foo", "com.example.bar", "UnicastSignal1", "", "com.example.SystemdActivatable1"); dbus_message_unref (m); /* The sender sends a message to a different activatable service. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2")) g_error ("OOM"); dbus_connection_send (f->caller, m, NULL); dbus_message_unref (m); /* This time systemd is already ready for it. */ while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* A malicious process tries to disrupt the activation. * In a more realistic scenario this would be another parallel * connection. */ m = dbus_message_new_signal ("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"); if (!dbus_message_set_destination (m, "org.freedesktop.DBus")) g_error ("OOM"); do { const char *unit = "dbus-com.example.SystemdActivatable2.service"; const char *error_name = "com.example.Malice"; const char *error_message = "I'm on yr bus, making yr activations fail"; if (!dbus_message_append_args (m, DBUS_TYPE_STRING, &unit, DBUS_TYPE_STRING, &error_name, DBUS_TYPE_STRING, &error_message, DBUS_TYPE_INVALID)) g_error ("OOM"); } while (0); dbus_connection_send (f->caller, m, NULL); dbus_message_unref (m); /* This is just to make sure that the malicious message has arrived and * been processed by the dbus-daemon, i.e. @caller won the race * with @activated. */ take_well_known_name (f, f->caller, "com.example.Sync"); /* The activatable service takes its name. Here I'm faking it by using * an existing connection; in real life it would be yet another * connection. */ take_well_known_name (f, f->activated, "com.example.SystemdActivatable2"); /* The message is delivered to the activatable service. */ while (f->activated_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->activated_message; f->activated_message = NULL; assert_signal (m, f->caller_name, "/foo", "com.example.bar", "UnicastSignal2", "", "com.example.SystemdActivatable2"); dbus_message_unref (m); /* A third activation. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3")) g_error ("OOM"); dbus_connection_send (f->caller, m, NULL); dbus_message_unref (m); while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* This time activation fails */ m = dbus_message_new_signal ("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"); do { const char *unit = "dbus-com.example.SystemdActivatable3.service"; const char *error_name = "com.example.Nope"; const char *error_message = "Computer says no"; if (!dbus_message_append_args (m, DBUS_TYPE_STRING, &unit, DBUS_TYPE_STRING, &error_name, DBUS_TYPE_STRING, &error_message, DBUS_TYPE_INVALID)) g_error ("OOM"); } while (0); if (!dbus_message_set_destination (m, "org.freedesktop.DBus")) g_error ("OOM"); dbus_connection_send (f->systemd, m, NULL); dbus_message_unref (m); } static void test_uae (Fixture *f, gconstpointer context) { DBusMessage *m; DBusPendingCall *pc; DBusMessageIter args_iter, arr_iter, entry_iter; const char *s; if (f->address == NULL) return; m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); /* Append an empty a{ss} (string => string dictionary). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "{ss}", &arr_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->caller, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); assert_method_reply (m, DBUS_SERVICE_DBUS, f->caller_name, ""); dbus_message_unref (m); /* The fake systemd connects to the bus. */ f->systemd = test_connect_to_bus (f->ctx, f->address); if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL)) g_error ("OOM"); f->systemd_name = dbus_bus_get_unique_name (f->systemd); take_well_known_name (f, f->systemd, "org.freedesktop.systemd1"); /* It gets the SetEnvironment */ while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; /* With activation, the destination is the well-known name */ assert_method_call (m, DBUS_SERVICE_DBUS, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment", "as"); dbus_message_iter_init (m, &args_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, DBUS_TYPE_ARRAY); g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_recurse (&args_iter, &arr_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==, DBUS_TYPE_INVALID); dbus_message_iter_next (&args_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, DBUS_TYPE_INVALID); dbus_message_unref (m); m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); { const char *k1 = "Key1", *v1 = "Value1", *k2 = "Key2", *v2 = "Value2"; /* Append a filled a{ss} (string => string dictionary). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "{ss}", &arr_iter) || !dbus_message_iter_open_container (&arr_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter) || !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &k1) || !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &v1) || !dbus_message_iter_close_container (&arr_iter, &entry_iter) || !dbus_message_iter_open_container (&arr_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter) || !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &k2) || !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &v2) || !dbus_message_iter_close_container (&arr_iter, &entry_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter)) g_error ("OOM"); } if (!dbus_connection_send_with_reply (f->caller, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); assert_method_reply (m, DBUS_SERVICE_DBUS, f->caller_name, ""); dbus_message_unref (m); while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; /* Without activation, the destination is the unique name */ assert_method_call (m, DBUS_SERVICE_DBUS, f->systemd_name, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment", "as"); dbus_message_iter_init (m, &args_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, DBUS_TYPE_ARRAY); g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_recurse (&args_iter, &arr_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_get_basic (&arr_iter, &s); g_assert_cmpstr (s, ==, "Key1=Value1"); dbus_message_iter_next (&arr_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_get_basic (&arr_iter, &s); g_assert_cmpstr (s, ==, "Key2=Value2"); dbus_message_iter_next (&arr_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==, DBUS_TYPE_INVALID); dbus_message_iter_next (&args_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, DBUS_TYPE_INVALID); dbus_message_unref (m); } static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { dbus_error_free (&f->e); g_clear_error (&f->ge); if (f->caller != NULL) { dbus_connection_close (f->caller); dbus_connection_unref (f->caller); f->caller = NULL; } if (f->systemd != NULL) { dbus_connection_remove_filter (f->systemd, systemd_filter, f); dbus_connection_close (f->systemd); dbus_connection_unref (f->systemd); f->systemd = NULL; } if (f->activated != NULL) { dbus_connection_remove_filter (f->activated, activated_filter, f); dbus_connection_close (f->activated); dbus_connection_unref (f->activated); f->activated = NULL; } test_kill_pid (f->daemon_pid); g_spawn_close_pid (f->daemon_pid); test_main_context_unref (f->ctx); g_free (f->address); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/sd-activation/activation", Fixture, NULL, setup, test_activation, teardown); g_test_add ("/sd-activation/uae", Fixture, NULL, setup, test_uae, teardown); return g_test_run (); } dbus-1.10.6/test/relay.c0000644000175000017500000002057012602773110015000 0ustar00smcvsmcv00000000000000/* Regression test for passing unmodified messages between connections * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "test-utils-glib.h" /* This is basically a miniature dbus-daemon. We relay messages from the client * on the left to the client on the right. * * left socket left dispatch right socket right * client ===========> server --------------> server ===========> client * conn conn conn conn * * In the real dbus-daemon, the client connections would be out-of-process, * but here we're cheating and doing everything in-process. */ typedef struct { TestMainContext *ctx; DBusError e; DBusServer *server; DBusConnection *left_client_conn; DBusConnection *left_server_conn; DBusConnection *right_server_conn; DBusConnection *right_client_conn; /* queue of DBusMessage received by right_client_conn */ GQueue messages; } Fixture; static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static DBusHandlerResult server_message_cb (DBusConnection *server_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (server_conn == f->left_server_conn); g_assert (f->right_server_conn != NULL); dbus_connection_send (f->right_server_conn, message, NULL); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult right_client_message_cb (DBusConnection *client_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (client_conn == f->right_client_conn); g_queue_push_tail (&f->messages, dbus_message_ref (message)); return DBUS_HANDLER_RESULT_HANDLED; } static void new_conn_cb (DBusServer *server, DBusConnection *server_conn, void *data) { Fixture *f = data; dbus_bool_t have_mem; if (f->left_server_conn == NULL) { f->left_server_conn = dbus_connection_ref (server_conn); have_mem = dbus_connection_add_filter (server_conn, server_message_cb, f, NULL); g_assert (have_mem); } else { g_assert (f->right_server_conn == NULL); f->right_server_conn = dbus_connection_ref (server_conn); } test_connection_setup (f->ctx, server_conn); } static void setup (Fixture *f, gconstpointer data G_GNUC_UNUSED) { f->ctx = test_main_context_get (); dbus_error_init (&f->e); g_queue_init (&f->messages); f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e); assert_no_error (&f->e); g_assert (f->server != NULL); dbus_server_set_new_connection_function (f->server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->server); } static void test_connect (Fixture *f, gconstpointer data G_GNUC_UNUSED) { dbus_bool_t have_mem; char *address; g_assert (f->left_server_conn == NULL); g_assert (f->right_server_conn == NULL); address = dbus_server_get_address (f->server); g_assert (address != NULL); f->left_client_conn = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->left_client_conn != NULL); test_connection_setup (f->ctx, f->left_client_conn); while (f->left_server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } f->right_client_conn = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->right_client_conn != NULL); test_connection_setup (f->ctx, f->right_client_conn); dbus_free (address); while (f->right_server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } have_mem = dbus_connection_add_filter (f->right_client_conn, right_client_message_cb, f, NULL); g_assert (have_mem); } static dbus_uint32_t send_one (Fixture *f, const char *member) { dbus_bool_t have_mem; dbus_uint32_t serial; DBusMessage *outgoing; outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", member); g_assert (outgoing != NULL); have_mem = dbus_connection_send (f->left_client_conn, outgoing, &serial); g_assert (have_mem); g_assert (serial != 0); dbus_message_unref (outgoing); return serial; } static void test_relay (Fixture *f, gconstpointer data) { DBusMessage *incoming; test_connect (f, data); send_one (f, "First"); send_one (f, "Second"); while (g_queue_get_length (&f->messages) < 2) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 2); incoming = g_queue_pop_head (&f->messages); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "First"); dbus_message_unref (incoming); incoming = g_queue_pop_head (&f->messages); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Second"); dbus_message_unref (incoming); } /* An arbitrary number of messages */ #define MANY 8192 static void test_limit (Fixture *f, gconstpointer data) { DBusMessage *incoming; guint i; test_connect (f, data); /* This was an attempt to reproduce fd.o #34393. It didn't work. */ g_test_bug ("34393"); dbus_connection_set_max_received_size (f->left_server_conn, 1); test_main_context_iterate (f->ctx, TRUE); for (i = 0; i < MANY; i++) { gchar *buf = g_strdup_printf ("Message%u", i); send_one (f, buf); g_free (buf); } i = 0; while (i < MANY) { while (g_queue_is_empty (&f->messages)) { test_main_context_iterate (f->ctx, TRUE); } while ((incoming = g_queue_pop_head (&f->messages)) != NULL) { i++; dbus_message_unref (incoming); } } } static void teardown (Fixture *f, gconstpointer data G_GNUC_UNUSED) { if (f->left_client_conn != NULL) { test_connection_shutdown(NULL, f->left_client_conn); dbus_connection_close (f->left_client_conn); dbus_connection_unref (f->left_client_conn); f->left_client_conn = NULL; } if (f->right_client_conn != NULL) { test_connection_shutdown(NULL, f->right_client_conn); dbus_connection_close (f->right_client_conn); dbus_connection_unref (f->right_client_conn); f->right_client_conn = NULL; } if (f->left_server_conn != NULL) { test_connection_shutdown(NULL, f->left_server_conn); dbus_connection_close (f->left_server_conn); dbus_connection_unref (f->left_server_conn); f->left_server_conn = NULL; } if (f->right_server_conn != NULL) { test_connection_shutdown(NULL, f->right_server_conn); dbus_connection_close (f->right_server_conn); dbus_connection_unref (f->right_server_conn); f->right_server_conn = NULL; } if (f->server != NULL) { dbus_server_disconnect (f->server); dbus_server_unref (f->server); f->server = NULL; } test_main_context_unref (f->ctx); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/connect", Fixture, NULL, setup, test_connect, teardown); g_test_add ("/relay", Fixture, NULL, setup, test_relay, teardown); g_test_add ("/limit", Fixture, NULL, setup, test_limit, teardown); return g_test_run (); } dbus-1.10.6/test/test-names.c0000644000175000017500000000365312602773110015747 0ustar00smcvsmcv00000000000000#include #include "test-utils.h" static DBusLoop *loop; static void die (const char *message) { fprintf (stderr, "*** test-names: %s", message); exit (1); } static void TestName(DBusConnection *connection, const char *name, int expectedSuccess) { DBusError error; dbus_error_init (&error); (void) dbus_bus_request_name (connection, name, 0, &error); if (dbus_error_is_set (&error)) { if (expectedSuccess) fprintf (stderr, "Error acquiring name '%s': %s\n", name, error.message); else fprintf (stdout, "Expected Error acquiring name '%s': %s\n", name, error.message); _dbus_verbose ("*** Failed to acquire name '%s': %s\n", name, error.message); dbus_error_free (&error); if (expectedSuccess) exit (1); } else { if (!expectedSuccess) fprintf (stderr, "Unexpected Success acquiring name '%s'\n", name); else fprintf (stdout, "Successfully acquired name '%s'\n", name); _dbus_verbose ("*** Managed to acquire name '%s'\n", name); if (!expectedSuccess) exit (1); } } int main (int argc, char **argv) { DBusError error; DBusConnection *connection; dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { fprintf (stderr, "*** Failed to open connection to system bus: %s\n", error.message); dbus_error_free (&error); return 1; } loop = _dbus_loop_new (); if (loop == NULL) die ("No memory\n"); if (!test_connection_setup (loop, connection)) die ("No memory\n"); TestName(connection, "org.freedesktop.DBus.Test", TRUE); TestName(connection, "org.freedesktop.DBus.Test-2", TRUE); TestName(connection, "org.freedesktop.DBus.Test_2", TRUE); #if 0 TestName(connection, "Test_2", TRUE); #endif _dbus_verbose ("*** Test service name exiting\n"); return 0; } dbus-1.10.6/test/monitor.c0000644000175000017500000014446212624705346015374 0ustar00smcvsmcv00000000000000/* Integration tests for monitor-mode D-Bus connections * * Copyright © 2010-2011 Nokia Corporation * Copyright © 2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "test-utils-glib.h" typedef struct { const char *config_file; const char * const *match_rules; gboolean care_about_our_names; } Config; typedef struct { const Config *config; TestMainContext *ctx; DBusError e; GError *ge; gchar *address; GPid daemon_pid; DBusConnection *monitor; DBusConnection *sender; DBusConnection *recipient; GQueue monitored; const char *monitor_name; const char *sender_name; const char *recipient_name; DBusConnection *systemd; const char *systemd_name; DBusMessage *systemd_message; DBusConnection *activated; const char *activated_name; DBusMessage *activated_message; } Fixture; static const char * const no_match_rules[] = { NULL }; static const char * const wildcard_match_rules[] = { "", NULL, FALSE }; static const char * const eavesdrop_match_rules[] = { "eavesdrop=true", NULL, FALSE }; static const char * const no_eavesdrop_match_rules[] = { "eavesdrop=false", NULL, FALSE }; static const char * const selective_match_rules[] = { "interface='com.example.Interesting'", "interface='com.example.Fun'", NULL, FALSE }; static Config forbidding_config = { "valid-config-files/forbidding.conf", NULL, FALSE }; static Config wildcard_config = { NULL, wildcard_match_rules, FALSE }; static Config selective_config = { NULL, selective_match_rules, FALSE }; static Config no_rules_config = { NULL, no_match_rules, FALSE }; static Config eavesdrop_config = { NULL, eavesdrop_match_rules, FALSE }; static Config no_eavesdrop_config = { NULL, no_eavesdrop_match_rules, FALSE }; #ifdef DBUS_UNIX static Config fake_systemd_config = { "valid-config-files/systemd-activation.conf", NULL, FALSE }; #endif static Config side_effects_config = { NULL, NULL, TRUE }; static inline const char * not_null2 (const char *x, const char *fallback) { if (x == NULL) return fallback; return x; } static inline const char * not_null (const char *x) { return not_null2 (x, "(null)"); } #define log_message(m) _log_message (m, __FILE__, __LINE__) G_GNUC_UNUSED static void _log_message (DBusMessage *m, const char *file, int line) { g_test_message ("%s:%d: message type %d (%s)", file, line, dbus_message_get_type (m), dbus_message_type_to_string (dbus_message_get_type (m))); g_test_message ("\tfrom: %s", not_null2 (dbus_message_get_sender (m), "(dbus-daemon)")); g_test_message ("\tto: %s", not_null2 (dbus_message_get_destination (m), "(broadcast)")); g_test_message ("\tpath: %s", not_null (dbus_message_get_path (m))); g_test_message ("\tinterface: %s", not_null (dbus_message_get_interface (m))); g_test_message ("\tmember: %s", not_null (dbus_message_get_member (m))); g_test_message ("\tsignature: %s", not_null (dbus_message_get_signature (m))); g_test_message ("\terror name: %s", not_null (dbus_message_get_error_name (m))); if (strcmp ("s", dbus_message_get_signature (m)) == 0) { DBusError e = DBUS_ERROR_INIT; const char *s; dbus_message_get_args (m, &e, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID); test_assert_no_error (&e); g_test_message ("\tstring payload: %s", s); } } /* these are macros so they get the right line number */ #define assert_hello(m) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, DBUS_SERVICE_DBUS); \ g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \ g_assert_cmpstr (dbus_message_get_member (m), ==, "Hello"); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, ""); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ } while (0) #define assert_hello_reply(m) \ do { \ DBusError _e = DBUS_ERROR_INIT; \ const char *_s; \ \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \ \ dbus_message_get_args (m, &_e, \ DBUS_TYPE_STRING, &_s, \ DBUS_TYPE_INVALID); \ test_assert_no_error (&_e); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \ } while (0) #define assert_name_acquired(m) \ do { \ DBusError _e = DBUS_ERROR_INIT; \ const char *_s; \ \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \ g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \ g_assert_cmpstr (dbus_message_get_member (m), ==, "NameAcquired"); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ \ dbus_message_get_args (m, &_e, \ DBUS_TYPE_STRING, &_s, \ DBUS_TYPE_INVALID); \ test_assert_no_error (&_e); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \ } while (0) #define assert_method_call(m, sender, \ destination, path, iface, method, signature) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \ g_assert_cmpstr (dbus_message_get_member (m), ==, method); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ } while (0) #define assert_signal(m, \ sender, path, iface, member, signature, \ destination) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, path); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \ g_assert_cmpstr (dbus_message_get_member (m), ==, member); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \ } while (0) #define assert_method_reply(m, sender, destination, signature) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \ } while (0) #define assert_error_reply(m, sender, destination, error_name) \ do { \ g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \ ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR)); \ g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \ g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \ g_assert_cmpstr (dbus_message_get_error_name (m), ==, error_name); \ g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \ g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \ g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \ g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \ } while (0) /* This is called after processing pending replies to our own method * calls, but before anything else. */ static DBusHandlerResult monitor_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; g_assert_cmpstr (dbus_message_get_interface (message), !=, "com.example.Tedious"); /* we are not interested in the monitor getting NameAcquired or NameLost * for most tests */ if (f->config == NULL || !f->config->care_about_our_names) { if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired") || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameLost")) { DBusError e = DBUS_ERROR_INIT; const char *s; dbus_message_get_args (message, &e, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID); test_assert_no_error (&e); if (strcmp (s, f->monitor_name) == 0) { /* ignore */ return DBUS_HANDLER_RESULT_HANDLED; } } } g_queue_push_tail (&f->monitored, dbus_message_ref (message)); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult recipient_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { g_assert_cmpstr (dbus_message_get_interface (message), !=, "com.example.CannotSend"); g_assert_cmpstr (dbus_message_get_interface (message), !=, "com.example.CannotReceive"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult systemd_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired") || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameLost")) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } g_assert (f->systemd_message == NULL); f->systemd_message = dbus_message_ref (message); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult activated_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired") || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameLost")) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } g_assert (f->activated_message == NULL); f->activated_message = dbus_message_ref (message); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void setup (Fixture *f, gconstpointer context) { f->config = context; f->ctx = test_main_context_get (); f->ge = NULL; dbus_error_init (&f->e); f->address = test_get_dbus_daemon (f->config ? f->config->config_file : NULL, TEST_USER_ME, &f->daemon_pid); if (f->address == NULL) return; f->monitor = test_connect_to_bus (f->ctx, f->address); f->monitor_name = dbus_bus_get_unique_name (f->monitor); f->sender = test_connect_to_bus (f->ctx, f->address); f->sender_name = dbus_bus_get_unique_name (f->sender); f->recipient = test_connect_to_bus (f->ctx, f->address); f->recipient_name = dbus_bus_get_unique_name (f->recipient); if (!dbus_connection_add_filter (f->monitor, monitor_filter, f, NULL)) g_error ("OOM"); if (!dbus_connection_add_filter (f->recipient, recipient_filter, f, NULL)) g_error ("OOM"); } static void become_monitor (Fixture *f) { DBusMessage *m; DBusPendingCall *pc; dbus_bool_t ok; DBusMessageIter appender, array_appender; const char * const *match_rules; int i; dbus_uint32_t zero = 0; dbus_connection_set_route_peer_messages (f->monitor, TRUE); if (f->config != NULL && f->config->match_rules != NULL) match_rules = f->config->match_rules; else match_rules = wildcard_match_rules; m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &appender); if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s", &array_appender)) g_error ("OOM"); for (i = 0; match_rules[i] != NULL; i++) { if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING, &match_rules[i])) g_error ("OOM"); } if (!dbus_message_iter_close_container (&appender, &array_appender) || !dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->monitor, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); ok = dbus_message_get_args (m, &f->e, DBUS_TYPE_INVALID); test_assert_no_error (&f->e); g_assert (ok); dbus_pending_call_unref (pc); dbus_message_unref (m); m = NULL; } /* * Test what happens if the method call arguments are invalid. */ static void test_invalid (Fixture *f, gconstpointer context) { DBusMessage *m; DBusPendingCall *pc; dbus_bool_t ok; DBusMessageIter appender, array_appender; dbus_uint32_t zero = 0; dbus_uint32_t invalid_flags = G_MAXUINT32; const char *s; if (f->address == NULL) return; dbus_connection_set_route_peer_messages (f->monitor, TRUE); /* Try to become a monitor but specify nonzero flags - not allowed */ m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &appender); if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s", &array_appender)) g_error ("OOM"); if (!dbus_message_iter_close_container (&appender, &array_appender) || !dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &invalid_flags)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->monitor, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR); g_assert_cmpstr (dbus_message_get_error_name (m), ==, DBUS_ERROR_INVALID_ARGS); /* Try to become a monitor but specify a bad match rule - * also not allowed */ dbus_pending_call_unref (pc); dbus_message_unref (m); m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &appender); if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s", &array_appender)) g_error ("OOM"); /* Syntactically incorrect match rule taken from #92298 - was probably * intended to be path='/modules/...' */ s = "interface='org.kde.walletd',member='/modules/kwalletd/org.kde.KWallet/walletOpened'"; if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING, &s) || !dbus_message_iter_close_container (&appender, &array_appender) || !dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero) || !dbus_connection_send_with_reply (f->monitor, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR); g_assert_cmpstr (dbus_message_get_error_name (m), ==, DBUS_ERROR_MATCH_RULE_INVALID); dbus_pending_call_unref (pc); dbus_message_unref (m); /* We did not become a monitor, so we can still call methods. */ pc = NULL; m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetId"); if (m == NULL) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->monitor, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); ok = dbus_message_get_args (m, &f->e, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID); test_assert_no_error (&f->e); g_assert (ok); g_assert_cmpstr (s, !=, NULL); g_assert_cmpstr (s, !=, ""); dbus_pending_call_unref (pc); dbus_message_unref (m); } /* * Test the side-effects of becoming a monitor. */ static void test_become_monitor (Fixture *f, gconstpointer context) { DBusMessage *m; int ret; dbus_bool_t got_unique = FALSE, got_a = FALSE, got_b = FALSE, got_c = FALSE; dbus_bool_t lost_unique = FALSE, lost_a = FALSE, lost_b = FALSE, lost_c = FALSE; if (f->address == NULL) return; ret = dbus_bus_request_name (f->monitor, "com.example.A", DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ret = dbus_bus_request_name (f->monitor, "com.example.B", DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); ret = dbus_bus_request_name (f->monitor, "com.example.C", DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); while (!got_unique || !got_a || !got_b || !got_c) { if (g_queue_is_empty (&f->monitored)) test_main_context_iterate (f->ctx, TRUE); while ((m = g_queue_pop_head (&f->monitored)) != NULL) { if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS, "NameAcquired")) { const char *name; dbus_bool_t ok = dbus_message_get_args (m, &f->e, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); test_assert_no_error (&f->e); g_assert (ok); if (g_str_equal (name, f->monitor_name)) { g_assert (!got_unique); got_unique = TRUE; } else if (g_str_equal (name, "com.example.A")) { g_assert (!got_a); got_a = TRUE; } else if (g_str_equal (name, "com.example.B")) { g_assert (!got_b); got_b = TRUE; } else { g_assert_cmpstr (name, ==, "com.example.C"); g_assert (!got_c); got_c = TRUE; } } else { g_error ("unexpected message %s.%s", dbus_message_get_interface (m), dbus_message_get_member (m)); } dbus_message_unref (m); } } become_monitor (f); while (!lost_unique || !lost_a || !lost_b || !lost_c) { if (g_queue_is_empty (&f->monitored)) test_main_context_iterate (f->ctx, TRUE); while ((m = g_queue_pop_head (&f->monitored)) != NULL) { if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS, "NameLost")) { const char *name; dbus_bool_t ok = dbus_message_get_args (m, &f->e, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); test_assert_no_error (&f->e); g_assert (ok); if (g_str_equal (name, f->monitor_name)) { g_assert (!lost_unique); lost_unique = TRUE; } else if (g_str_equal (name, "com.example.A")) { g_assert (!lost_a); lost_a = TRUE; } else if (g_str_equal (name, "com.example.B")) { g_assert (!lost_b); lost_b = TRUE; } else { g_assert_cmpstr (name, ==, "com.example.C"); g_assert (!lost_c); lost_c = TRUE; } } else { g_error ("unexpected message %s.%s", dbus_message_get_interface (m), dbus_message_get_member (m)); } dbus_message_unref (m); } } /* Calling methods is forbidden; we get disconnected. */ dbus_bus_add_match (f->monitor, "", &f->e); g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY); g_assert (!dbus_connection_get_is_connected (f->monitor)); while (TRUE) { if (g_queue_is_empty (&f->monitored)) test_main_context_iterate (f->ctx, TRUE); /* When we iterate all the connection's messages, we see ourselves * losing all our names, then we're disconnected. */ while ((m = g_queue_pop_head (&f->monitored)) != NULL) { if (dbus_message_is_signal (m, DBUS_INTERFACE_LOCAL, "Disconnected")) { dbus_message_unref (m); goto disconnected; } else { g_error ("unexpected message %s.%s", dbus_message_get_interface (m), dbus_message_get_member (m)); } dbus_message_unref (m); } } disconnected: g_assert (lost_a); g_assert (lost_b); g_assert (lost_c); } static void test_broadcast (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; dbus_bus_add_match (f->recipient, "type='signal'", &f->e); test_assert_no_error (&f->e); become_monitor (f); m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal1"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal2"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal3"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 3) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "BroadcastSignal1", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "BroadcastSignal2", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "BroadcastSignal3", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_forbidden_broadcast (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; dbus_bus_add_match (f->recipient, "type='signal'", &f->e); test_assert_no_error (&f->e); become_monitor (f); m = dbus_message_new_signal ("/foo", "com.example.CannotSend", "BroadcastSignal1"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.CannotReceive", "BroadcastSignal2"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.CannotSend", "BroadcastSignal3"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 6) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend", "BroadcastSignal1", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotReceive", "BroadcastSignal2", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend", "BroadcastSignal3", "", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_unicast_signal (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; become_monitor (f); m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 3) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal1", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal2", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal3", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_forbidden (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; become_monitor (f); m = dbus_message_new_signal ("/foo", "com.example.CannotSend", "UnicastSignal1"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.CannotReceive", "UnicastSignal2"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.CannotSend", "UnicastSignal3"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 6) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend", "UnicastSignal1", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotReceive", "UnicastSignal2", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend", "UnicastSignal3", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_method_call (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; become_monitor (f); /* regression test for * https://bugs.freedesktop.org/show_bug.cgi?id=90952 */ m = dbus_message_new_method_call (f->recipient_name, "/foo", DBUS_INTERFACE_PEER, "Ping"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, f->recipient_name, "/foo", DBUS_INTERFACE_PEER, "Ping", ""); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_method_reply (m, f->recipient_name, f->sender_name, ""); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); m = dbus_message_new_method_call (f->recipient_name, "/foo", "com.example.bar", "Call1"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, f->recipient_name, "/foo", "com.example.bar", "Call1", ""); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, f->recipient_name, f->sender_name, DBUS_ERROR_UNKNOWN_METHOD); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_forbidden_method_call (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; become_monitor (f); m = dbus_message_new_method_call (f->recipient_name, "/foo", "com.example.CannotSend", "Call1"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, f->recipient_name, "/foo", "com.example.CannotSend", "Call1", ""); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); m = dbus_message_new_method_call (f->recipient_name, "/foo", "com.example.CannotReceive", "Call2"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, f->recipient_name, "/foo", "com.example.CannotReceive", "Call2", ""); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, DBUS_ERROR_ACCESS_DENIED); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_dbus_daemon (Fixture *f, gconstpointer context) { DBusMessage *m; int res; if (f->address == NULL) return; become_monitor (f); res = dbus_bus_request_name (f->sender, "com.example.Sender", DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (res, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); res = dbus_bus_release_name (f->sender, "com.example.Sender", &f->e); test_assert_no_error (&f->e); g_assert_cmpint (res, ==, DBUS_RELEASE_NAME_REPLY_RELEASED); while (g_queue_get_length (&f->monitored) < 8) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "RequestName", "su"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged", "sss", NULL); dbus_message_unref (m); /* FIXME: should we get this? */ m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameAcquired", "s", f->sender_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ReleaseName", "s"); dbus_message_unref (m); /* FIXME: should we get this? */ m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameLost", "s", f->sender_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged", "sss", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } static void test_selective (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; /* Match rules added before becoming a monitor should be cleared: * if they weren't, this test would get Interesting twice, then Tedious, * and only see Fun after that. */ dbus_bus_add_match (f->monitor, "eavesdrop='true',interface='com.example.Interesting'", &f->e); test_assert_no_error (&f->e); dbus_bus_add_match (f->monitor, "eavesdrop='true',interface='com.example.Tedious'", &f->e); test_assert_no_error (&f->e); become_monitor (f); m = dbus_message_new_signal ("/foo", "com.example.Interesting", "UnicastSignal1"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.Tedious", "UnicastSignal2"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); m = dbus_message_new_signal ("/foo", "com.example.Fun", "UnicastSignal3"); if (!dbus_message_set_destination (m, f->recipient_name)) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); /* We get the interesting signal and the fun signal, but not the tedious * signal. */ m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.Interesting", "UnicastSignal1", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.Fun", "UnicastSignal3", "", f->recipient_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); g_assert (m == NULL); } #ifdef DBUS_UNIX /* currently only used for the systemd activation test */ static void expect_new_connection (Fixture *f) { DBusMessage *m; while (g_queue_get_length (&f->monitored) < 4) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_hello (m); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_hello_reply (m); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged", "sss", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_name_acquired (m); dbus_message_unref (m); } /* currently only used for the systemd activation test */ static void take_well_known_name (Fixture *f, DBusConnection *connection, const char *name) { int ret; ret = dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e); test_assert_no_error (&f->e); g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); } /* currently only used for the systemd activation test */ static void expect_take_well_known_name (Fixture *f, DBusConnection *connection, const char *name) { DBusMessage *m; const char *connection_name = dbus_bus_get_unique_name (connection); while (g_queue_get_length (&f->monitored) < 4) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_method_call (m, connection_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "RequestName", "su"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged", "sss", NULL); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameAcquired", "s", connection_name); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_method_reply (m, DBUS_SERVICE_DBUS, connection_name, "u"); dbus_message_unref (m); } static void test_activation (Fixture *f, gconstpointer context) { DBusMessage *m; if (f->address == NULL) return; become_monitor (f); /* The sender sends a message to an activatable service. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1")) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); /* We observe the activation request, and the message that caused it, * before systemd has even joined the bus. */ while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal1", "", "com.example.SystemdActivatable1"); dbus_message_unref (m); /* The fake systemd connects to the bus. */ f->systemd = test_connect_to_bus (f->ctx, f->address); if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL)) g_error ("OOM"); f->systemd_name = dbus_bus_get_unique_name (f->systemd); expect_new_connection (f); take_well_known_name (f, f->systemd, "org.freedesktop.systemd1"); expect_take_well_known_name (f, f->systemd, "org.freedesktop.systemd1"); /* It gets its activation request. */ while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* systemd starts the activatable service. */ f->activated = test_connect_to_bus (f->ctx, f->address); if (!dbus_connection_add_filter (f->activated, activated_filter, f, NULL)) g_error ("OOM"); f->activated_name = dbus_bus_get_unique_name (f->activated); expect_new_connection (f); take_well_known_name (f, f->activated, "com.example.SystemdActivatable1"); expect_take_well_known_name (f, f->activated, "com.example.SystemdActivatable1"); /* The message is delivered to the activatable service. */ while (f->activated_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->activated_message; f->activated_message = NULL; assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal1", "", "com.example.SystemdActivatable1"); dbus_message_unref (m); /* The sender sends a message to a different activatable service. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2")) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); /* This time systemd is already ready for it. */ while (g_queue_get_length (&f->monitored) < 2 || f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* The monitor sees the activation request and the signal that * prompted it.*/ m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal2", "", "com.example.SystemdActivatable2"); dbus_message_unref (m); /* The activatable service takes its name. Here I'm faking it by using * an existing connection. */ take_well_known_name (f, f->activated, "com.example.SystemdActivatable2"); /* The message is delivered to the activatable service. * Implementation detail: the monitor sees this happen before it even * sees that the name request happened, which is pretty odd. */ while (f->activated_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->activated_message; f->activated_message = NULL; assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal2", "", "com.example.SystemdActivatable2"); dbus_message_unref (m); expect_take_well_known_name (f, f->activated, "com.example.SystemdActivatable2"); /* A third activation. */ m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3"); if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3")) g_error ("OOM"); dbus_connection_send (f->sender, m, NULL); dbus_message_unref (m); /* Once again, we see the activation request and the reason. */ while (g_queue_get_length (&f->monitored) < 2) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); m = g_queue_pop_head (&f->monitored); assert_signal (m, f->sender_name, "/foo", "com.example.bar", "UnicastSignal3", "", "com.example.SystemdActivatable3"); dbus_message_unref (m); /* systemd gets the request too. */ while (f->systemd_message == NULL) test_main_context_iterate (f->ctx, TRUE); m = f->systemd_message; f->systemd_message = NULL; assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.systemd1.Activator", "ActivationRequest", "s", "org.freedesktop.systemd1"); dbus_message_unref (m); /* This time activation fails */ m = dbus_message_new_signal ("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"); do { const char *unit = "dbus-com.example.SystemdActivatable3.service"; const char *error_name = "com.example.Nope"; const char *error_message = "Computer says no"; if (!dbus_message_append_args (m, DBUS_TYPE_STRING, &unit, DBUS_TYPE_STRING, &error_name, DBUS_TYPE_STRING, &error_message, DBUS_TYPE_INVALID)) g_error ("OOM"); } while (0); if (!dbus_message_set_destination (m, "org.freedesktop.DBus")) g_error ("OOM"); dbus_connection_send (f->systemd, m, NULL); dbus_message_unref (m); /* The monitor sees activation fail */ /* Once again, we see the activation request and the reason. */ while (g_queue_get_length (&f->monitored) < 1) test_main_context_iterate (f->ctx, TRUE); m = g_queue_pop_head (&f->monitored); assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "com.example.Nope"); dbus_message_unref (m); } #endif /* DBUS_UNIX */ static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { dbus_error_free (&f->e); g_clear_error (&f->ge); if (f->monitor != NULL) { dbus_connection_remove_filter (f->monitor, monitor_filter, f); dbus_connection_close (f->monitor); dbus_connection_unref (f->monitor); f->monitor = NULL; } if (f->sender != NULL) { dbus_connection_close (f->sender); dbus_connection_unref (f->sender); f->sender = NULL; } if (f->recipient != NULL) { dbus_connection_remove_filter (f->recipient, recipient_filter, f); dbus_connection_close (f->recipient); dbus_connection_unref (f->recipient); f->recipient = NULL; } if (f->systemd != NULL) { dbus_connection_remove_filter (f->systemd, systemd_filter, f); dbus_connection_close (f->systemd); dbus_connection_unref (f->systemd); f->systemd = NULL; } if (f->activated != NULL) { dbus_connection_remove_filter (f->activated, activated_filter, f); dbus_connection_close (f->activated); dbus_connection_unref (f->activated); f->activated = NULL; } test_kill_pid (f->daemon_pid); g_spawn_close_pid (f->daemon_pid); test_main_context_unref (f->ctx); g_queue_foreach (&f->monitored, (GFunc) dbus_message_unref, NULL); g_queue_clear (&f->monitored); g_free (f->address); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/monitor/invalid", Fixture, NULL, setup, test_invalid, teardown); g_test_add ("/monitor/become", Fixture, &side_effects_config, setup, test_become_monitor, teardown); g_test_add ("/monitor/broadcast", Fixture, NULL, setup, test_broadcast, teardown); g_test_add ("/monitor/forbidden-broadcast", Fixture, &forbidding_config, setup, test_forbidden_broadcast, teardown); g_test_add ("/monitor/unicast-signal", Fixture, NULL, setup, test_unicast_signal, teardown); g_test_add ("/monitor/forbidden", Fixture, &forbidding_config, setup, test_forbidden, teardown); g_test_add ("/monitor/method-call", Fixture, NULL, setup, test_method_call, teardown); g_test_add ("/monitor/forbidden-method", Fixture, &forbidding_config, setup, test_forbidden_method_call, teardown); g_test_add ("/monitor/dbus-daemon", Fixture, NULL, setup, test_dbus_daemon, teardown); g_test_add ("/monitor/selective", Fixture, &selective_config, setup, test_selective, teardown); g_test_add ("/monitor/wildcard", Fixture, &wildcard_config, setup, test_unicast_signal, teardown); g_test_add ("/monitor/no-rule", Fixture, &no_rules_config, setup, test_unicast_signal, teardown); g_test_add ("/monitor/eavesdrop", Fixture, &eavesdrop_config, setup, test_unicast_signal, teardown); g_test_add ("/monitor/no-eavesdrop", Fixture, &no_eavesdrop_config, setup, test_unicast_signal, teardown); #ifdef DBUS_UNIX /* this relies on the systemd activation code path */ g_test_add ("/monitor/activation", Fixture, &fake_systemd_config, setup, test_activation, teardown); #endif return g_test_run (); } dbus-1.10.6/test/marshal.c0000644000175000017500000002215112602773110015310 0ustar00smcvsmcv00000000000000/* Simple sanity-check for D-Bus message serialization. * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include "test-utils-glib.h" typedef struct { DBusError e; } Fixture; static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static void setup (Fixture *f, gconstpointer arg G_GNUC_UNUSED) { dbus_error_init (&f->e); } /* this is meant to be obviously correct, not efficient! */ static guint32 get_uint32 (const gchar *blob, gsize offset, char endian) { if (endian == 'l') { return blob[offset] | (blob[offset + 1] << 8) | (blob[offset + 2] << 16) | (blob[offset + 3] << 24); } else if (endian == 'B') { return (blob[offset] << 24) | (blob[offset + 1] << 16) | (blob[offset + 2] << 8) | blob[offset + 3]; } else { g_assert_not_reached (); } } #define BLOB_LENGTH (sizeof (le_blob) - 1) #define OFFSET_BODY_LENGTH (4) #define OFFSET_SERIAL (8) const gchar le_blob[] = /* byte 0 */ /* yyyyuu fixed headers */ "l" /* little-endian */ "\2" /* reply (which is the simplest message) */ "\2" /* no auto-starting */ "\1" /* D-Bus version = 1 */ /* byte 4 */ "\4\0\0\0" /* bytes in body = 4 */ /* byte 8 */ "\x78\x56\x34\x12" /* serial number = 0x12345678 */ /* byte 12 */ /* a(uv) variable headers start here */ "\x0f\0\0\0" /* bytes in array of variable headers = 15 */ /* pad to 8-byte boundary = nothing */ /* byte 16 */ "\5" /* in reply to: */ "\1u\0" /* variant signature = u */ /* pad to 4-byte boundary = nothing */ "\x12\xef\xcd\xab" /* 0xabcdef12 */ /* pad to 8-byte boundary = nothing */ /* byte 24 */ "\x08" /* signature: */ "\1g\0" /* variant signature = g */ "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ "\0" /* pad to 8-byte boundary for body */ /* body; byte 32 */ "\xef\xbe\xad\xde" /* 0xdeadbeef */ ; const gchar be_blob[] = /* byte 0 */ /* yyyyuu fixed headers */ "B" /* big-endian */ "\2" /* reply (which is the simplest message) */ "\2" /* no auto-starting */ "\1" /* D-Bus version = 1 */ /* byte 4 */ "\0\0\0\4" /* bytes in body = 4 */ /* byte 8 */ "\x12\x34\x56\x78" /* serial number = 0x12345678 */ /* byte 12 */ /* a(uv) variable headers start here */ "\0\0\0\x0f" /* bytes in array of variable headers = 15 */ /* pad to 8-byte boundary = nothing */ /* byte 16 */ "\5" /* in reply to: */ "\1u\0" /* variant signature = u */ /* pad to 4-byte boundary = nothing */ "\xab\xcd\xef\x12" /* 0xabcdef12 */ /* pad to 8-byte boundary = nothing */ /* byte 24 */ "\x08" /* signature: */ "\1g\0" /* variant signature = g */ "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ "\0" /* pad to 8-byte boundary for body */ /* body; byte 32 */ "\xde\xad\xbe\xef" /* 0xdeadbeef */ ; static void test_endian (Fixture *f, gconstpointer arg) { const gchar *blob = arg; char *output; DBusMessage *m; int len; dbus_uint32_t u; dbus_bool_t ok; g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob)); g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4); g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==, 0x12345678u); len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob)); /* everything in the string except the implicit "\0" at the end is part of * the message */ g_assert_cmpint (len, ==, BLOB_LENGTH); m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e); assert_no_error (&f->e); g_assert (m != NULL); g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u); g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u); g_assert_cmpstr (dbus_message_get_signature (m), ==, "u"); /* Implementation detail: appending to the message results in it being * byteswapped into compiler byte order, which exposed a bug in libdbus, * fd.o #38120. (If that changes, this test might not exercise that * particular bug but will still be valid.) */ u = 0xdecafbadu; ok = dbus_message_append_args (m, DBUS_TYPE_UINT32, &u, DBUS_TYPE_INVALID); g_assert (ok); dbus_message_marshal (m, &output, &len); g_assert (output[0] == 'l' || output[0] == 'B'); /* the single-byte fields are unaffected, even if the endianness was * swapped */ g_assert_cmpint (output[1], ==, blob[1]); g_assert_cmpint (output[2], ==, blob[2]); g_assert_cmpint (output[3], ==, blob[3]); /* the length and serial are in the new endianness, the length has expanded * to 8, and the serial is correct */ g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8); g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==, 0x12345678u); /* the second "u" in the signature replaced a padding byte, so only * the length of the body changed */ g_assert_cmpint (len, ==, BLOB_LENGTH + 4); } static void test_needed (Fixture *f, gconstpointer arg) { const gchar *blob = arg; /* We need at least 16 bytes to know how long the message is - that's just * a fact of the D-Bus protocol. */ g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 0), ==, 0); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 15), ==, 0); /* This is enough that we should be able to tell how much we need. */ g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 16), ==, BLOB_LENGTH); /* The header is 32 bytes long (here), so that's another interesting * boundary. */ g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 31), ==, BLOB_LENGTH); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 32), ==, BLOB_LENGTH); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, 33), ==, BLOB_LENGTH); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH - 1), ==, BLOB_LENGTH); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH), ==, BLOB_LENGTH); g_assert_cmpint ( dbus_message_demarshal_bytes_needed (blob, sizeof (be_blob)), ==, BLOB_LENGTH); } static void teardown (Fixture *f, gconstpointer arg G_GNUC_UNUSED) { dbus_error_free (&f->e); } int main (int argc, char **argv) { int ret; char *aligned_le_blob; char *aligned_be_blob; test_init (&argc, &argv); /* We have to pass in a buffer that's at least "default aligned", * i.e. on GNU systems to 8 or 16. The linker may have only given * us byte-alignment for the char[] static variables. */ aligned_le_blob = g_malloc (sizeof (le_blob)); memcpy (aligned_le_blob, le_blob, sizeof (le_blob)); aligned_be_blob = g_malloc (sizeof (be_blob)); memcpy (aligned_be_blob, be_blob, sizeof (be_blob)); g_test_add ("/demarshal/le", Fixture, aligned_le_blob, setup, test_endian, teardown); g_test_add ("/demarshal/be", Fixture, aligned_be_blob, setup, test_endian, teardown); g_test_add ("/demarshal/needed/le", Fixture, aligned_le_blob, setup, test_needed, teardown); g_test_add ("/demarshal/needed/be", Fixture, aligned_be_blob, setup, test_needed, teardown); ret = g_test_run (); g_free (aligned_le_blob); g_free (aligned_be_blob); return ret; } dbus-1.10.6/test/loopback.c0000644000175000017500000002506512602773110015462 0ustar00smcvsmcv00000000000000/* Simple sanity-check for loopback through TCP and Unix sockets. * * Author: Simon McVittie * Copyright © 2010-2012 Nokia Corporation * Copyright © 2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include "test-utils-glib.h" typedef struct { TestMainContext *ctx; DBusError e; DBusServer *server; DBusConnection *server_conn; /* queue of DBusMessage */ GQueue server_messages; DBusConnection *client_conn; gchar *tmp_runtime_dir; gchar *saved_runtime_dir; } Fixture; static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static DBusHandlerResult server_message_cb (DBusConnection *server_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (server_conn == f->server_conn); g_queue_push_tail (&f->server_messages, dbus_message_ref (message)); return DBUS_HANDLER_RESULT_HANDLED; } static void new_conn_cb (DBusServer *server, DBusConnection *server_conn, void *data) { Fixture *f = data; dbus_bool_t have_mem; g_assert (f->server_conn == NULL); f->server_conn = dbus_connection_ref (server_conn); test_connection_setup (f->ctx, server_conn); have_mem = dbus_connection_add_filter (server_conn, server_message_cb, f, NULL); g_assert (have_mem); } static void setup (Fixture *f, gconstpointer addr) { f->ctx = test_main_context_get (); dbus_error_init (&f->e); g_queue_init (&f->server_messages); f->server = dbus_server_listen (addr, &f->e); assert_no_error (&f->e); g_assert (f->server != NULL); dbus_server_set_new_connection_function (f->server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->server); } #ifdef DBUS_UNIX static void setup_runtime (Fixture *f, gconstpointer addr) { char *listening_at; GError *error = NULL; /* this is chosen to be something needing escaping */ f->tmp_runtime_dir = g_dir_make_tmp ("dbus=daemon=test.XXXXXX", &error); g_assert_no_error (error); /* we're relying on being single-threaded for this to be safe */ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR")); g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE); setup (f, addr); listening_at = dbus_server_get_address (f->server); g_test_message ("listening at %s", listening_at); g_assert (g_str_has_prefix (listening_at, "unix:path=")); g_assert (strstr (listening_at, "dbus%3ddaemon%3dtest.") != NULL); g_assert (strstr (listening_at, "/bus,") != NULL || g_str_has_suffix (listening_at, "/bus")); dbus_free (listening_at); } static void setup_no_runtime (Fixture *f, gconstpointer addr) { char *listening_at; /* we're relying on being single-threaded for this to be safe */ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR")); g_unsetenv ("XDG_RUNTIME_DIR"); setup (f, addr); listening_at = dbus_server_get_address (f->server); g_test_message ("listening at %s", listening_at); /* we have fallen back to something in /tmp, either abstract or not */ g_assert (g_str_has_prefix (listening_at, "unix:")); g_assert (strstr (listening_at, "=/tmp/") != NULL); dbus_free (listening_at); } #endif static void test_connect (Fixture *f, gconstpointer addr G_GNUC_UNUSED) { g_assert (f->server_conn == NULL); f->client_conn = dbus_connection_open_private ( dbus_server_get_address (f->server), &f->e); assert_no_error (&f->e); g_assert (f->client_conn != NULL); test_connection_setup (f->ctx, f->client_conn); while (f->server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } } static void test_bad_guid (Fixture *f, gconstpointer addr G_GNUC_UNUSED) { DBusMessage *incoming; gchar *address = g_strdup (dbus_server_get_address (f->server)); gchar *guid; g_test_bug ("39720"); g_assert (f->server_conn == NULL); g_assert (strstr (address, "guid=") != NULL); guid = strstr (address, "guid="); g_assert_cmpuint (strlen (guid), >=, 5 + 32); /* Change the first char of the guid to something different */ if (guid[5] == '0') guid[5] = 'f'; else guid[5] = '0'; f->client_conn = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->client_conn != NULL); test_connection_setup (f->ctx, f->client_conn); while (f->server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } /* We get disconnected */ while (g_queue_is_empty (&f->server_messages)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1); incoming = g_queue_pop_head (&f->server_messages); g_assert (!dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, DBUS_INTERFACE_LOCAL); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Disconnected"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (incoming), ==, ""); g_assert_cmpstr (dbus_message_get_path (incoming), ==, DBUS_PATH_LOCAL); dbus_message_unref (incoming); g_free (address); } static void test_message (Fixture *f, gconstpointer addr) { dbus_bool_t have_mem; dbus_uint32_t serial; DBusMessage *outgoing, *incoming; test_connect (f, addr); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); have_mem = dbus_connection_send (f->client_conn, outgoing, &serial); g_assert (have_mem); g_assert (serial != 0); while (g_queue_is_empty (&f->server_messages)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1); incoming = g_queue_pop_head (&f->server_messages); g_assert (!dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (incoming), ==, ""); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial); dbus_message_unref (incoming); dbus_message_unref (outgoing); } static void teardown (Fixture *f, gconstpointer addr G_GNUC_UNUSED) { if (f->client_conn != NULL) { dbus_connection_close (f->client_conn); dbus_connection_unref (f->client_conn); f->client_conn = NULL; } if (f->server_conn != NULL) { dbus_connection_close (f->server_conn); dbus_connection_unref (f->server_conn); f->server_conn = NULL; } if (f->server != NULL) { dbus_server_disconnect (f->server); dbus_server_unref (f->server); f->server = NULL; } test_main_context_unref (f->ctx); } #ifdef DBUS_UNIX static void teardown_no_runtime (Fixture *f, gconstpointer addr) { teardown (f, addr); /* we're relying on being single-threaded for this to be safe */ if (f->saved_runtime_dir != NULL) g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE); else g_unsetenv ("XDG_RUNTIME_DIR"); g_free (f->saved_runtime_dir); } static void teardown_runtime (Fixture *f, gconstpointer addr) { gchar *path; teardown (f, addr); /* the socket may exist */ path = g_strdup_printf ("%s/bus", f->tmp_runtime_dir); g_assert (g_remove (path) == 0 || errno == ENOENT); g_free (path); /* there shouldn't be anything else in there */ g_assert_cmpint (g_rmdir (f->tmp_runtime_dir), ==, 0); /* we're relying on being single-threaded for this to be safe */ if (f->saved_runtime_dir != NULL) g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE); else g_unsetenv ("XDG_RUNTIME_DIR"); g_free (f->saved_runtime_dir); g_free (f->tmp_runtime_dir); } #endif int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/connect/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_connect, teardown); g_test_add ("/message/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_message, teardown); g_test_add ("/connect/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup, test_connect, teardown); g_test_add ("/message/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup, test_message, teardown); #ifdef DBUS_UNIX g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup, test_connect, teardown); g_test_add ("/message/unix", Fixture, "unix:tmpdir=/tmp", setup, test_message, teardown); g_test_add ("/connect/unix/runtime", Fixture, "unix:runtime=yes;unix:tmpdir=/tmp", setup_runtime, test_connect, teardown_runtime); g_test_add ("/connect/unix/no-runtime", Fixture, "unix:runtime=yes;unix:tmpdir=/tmp", setup_no_runtime, test_connect, teardown_no_runtime); #endif g_test_add ("/message/bad-guid", Fixture, "tcp:host=127.0.0.1", setup, test_bad_guid, teardown); return g_test_run (); } dbus-1.10.6/test/fdpass.c0000644000175000017500000006650612622707003015155 0ustar00smcvsmcv00000000000000/* * Copyright © 2010-2012 Nokia Corporation * Copyright © 2014 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #ifdef G_OS_UNIX # include # include # include # ifdef HAVE_SYS_RESOURCE_H # include # endif # include # include # include # include #endif #include "test-utils-glib.h" /* Arbitrary; included here to avoid relying on the default */ #define MAX_MESSAGE_UNIX_FDS 20 /* This test won't work on Linux unless this is true. */ _DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS <= 253); /* Arbitrary; included here to avoid relying on the default. */ #define MAX_INCOMING_UNIX_FDS (MAX_MESSAGE_UNIX_FDS * 4) /* Arbitrary, except that MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES should be * less than the process's file descriptor limit. */ #define SOME_MESSAGES 20 /* To cover some situations on Linux we want this to be true. */ _DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES > 256); /* Linux won't allow more than 253 fds per sendmsg(). */ #define TOO_MANY_FDS 255 _DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS < TOO_MANY_FDS); /* As in test/relay.c, this is a miniature dbus-daemon: we relay messages * from the client on the left to the client on the right. * * left socket left dispatch right socket right * client ===========> server --------------> server ===========> client * conn conn conn conn */ typedef struct { TestMainContext *ctx; DBusError e; DBusServer *server; DBusConnection *left_client_conn; DBusConnection *left_server_conn; DBusConnection *right_server_conn; DBusConnection *right_client_conn; /* queue of DBusMessage received by right_client_conn */ GQueue messages; int fd_before; } Fixture; static void oom (const gchar *doing) G_GNUC_NORETURN; static void oom (const gchar *doing) { g_error ("out of memory (%s)", doing); abort (); } static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static DBusHandlerResult left_server_message_cb (DBusConnection *server_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (server_conn == f->left_server_conn); g_assert (f->right_server_conn != NULL); dbus_connection_send (f->right_server_conn, message, NULL); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult right_client_message_cb (DBusConnection *client_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (client_conn == f->right_client_conn); g_queue_push_tail (&f->messages, dbus_message_ref (message)); return DBUS_HANDLER_RESULT_HANDLED; } static void new_conn_cb (DBusServer *server, DBusConnection *server_conn, void *data) { Fixture *f = data; dbus_connection_set_max_message_unix_fds (server_conn, MAX_MESSAGE_UNIX_FDS); dbus_connection_set_max_received_unix_fds (server_conn, MAX_INCOMING_UNIX_FDS); if (f->left_server_conn == NULL) { f->left_server_conn = dbus_connection_ref (server_conn); if (!dbus_connection_add_filter (server_conn, left_server_message_cb, f, NULL)) oom ("adding filter"); } else { g_assert (f->right_server_conn == NULL); f->right_server_conn = dbus_connection_ref (server_conn); } test_connection_setup (f->ctx, server_conn); } static void test_connect (Fixture *f, gboolean should_support_fds) { char *address; g_assert (f->left_server_conn == NULL); g_assert (f->right_server_conn == NULL); address = dbus_server_get_address (f->server); g_assert (address != NULL); f->left_client_conn = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->left_client_conn != NULL); test_connection_setup (f->ctx, f->left_client_conn); /* The left client connection is allowed to behave abusively. */ dbus_connection_set_max_message_unix_fds (f->left_client_conn, 1000); dbus_connection_set_max_received_unix_fds (f->left_client_conn, 1000000); while (f->left_server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } f->right_client_conn = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->right_client_conn != NULL); test_connection_setup (f->ctx, f->right_client_conn); dbus_free (address); while (f->right_server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } if (!dbus_connection_add_filter (f->right_client_conn, right_client_message_cb, f, NULL)) oom ("adding filter"); /* The right client connection is allowed to queue all the messages. */ dbus_connection_set_max_message_unix_fds (f->right_client_conn, 1000); dbus_connection_set_max_received_unix_fds (f->right_client_conn, 1000000); while (!dbus_connection_get_is_authenticated (f->left_client_conn) || !dbus_connection_get_is_authenticated (f->right_client_conn) || !dbus_connection_get_is_authenticated (f->left_server_conn) || !dbus_connection_get_is_authenticated (f->right_server_conn)) { test_progress ('*'); test_main_context_iterate (f->ctx, TRUE); } if (!should_support_fds) return; if (!dbus_connection_can_send_type (f->left_client_conn, DBUS_TYPE_UNIX_FD)) g_error ("left client connection cannot send Unix fds"); if (!dbus_connection_can_send_type (f->left_server_conn, DBUS_TYPE_UNIX_FD)) g_error ("left server connection cannot send Unix fds"); if (!dbus_connection_can_send_type (f->right_client_conn, DBUS_TYPE_UNIX_FD)) g_error ("right client connection cannot send Unix fds"); if (!dbus_connection_can_send_type (f->right_server_conn, DBUS_TYPE_UNIX_FD)) g_error ("right server connection cannot send Unix fds"); } static void setup_common (Fixture *f, const char *address) { f->ctx = test_main_context_get (); dbus_error_init (&f->e); g_queue_init (&f->messages); f->server = dbus_server_listen (address, &f->e); assert_no_error (&f->e); g_assert (f->server != NULL); dbus_server_set_new_connection_function (f->server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->server); } static void setup_unsupported (Fixture *f, gconstpointer data G_GNUC_UNUSED) { setup_common (f, "tcp:host=127.0.0.1"); } static void setup (Fixture *f, gconstpointer data G_GNUC_UNUSED) { #ifdef HAVE_UNIX_FD_PASSING /* We assume that anything with fd-passing supports the unix: transport */ setup_common (f, "unix:tmpdir=/tmp"); f->fd_before = open ("/dev/null", O_RDONLY); /* this should succeed on any reasonable Unix */ if (f->fd_before < 0) g_error ("cannot open /dev/null for reading: %s", g_strerror (errno)); _dbus_fd_set_close_on_exec (f->fd_before); #endif } static void test_unsupported (Fixture *f, gconstpointer data) { test_connect (f, FALSE); if (dbus_connection_can_send_type (f->left_client_conn, DBUS_TYPE_UNIX_FD)) g_error ("left client connection claims it can send Unix fds"); if (dbus_connection_can_send_type (f->left_server_conn, DBUS_TYPE_UNIX_FD)) g_error ("left server connection claims it can send Unix fds"); if (dbus_connection_can_send_type (f->right_client_conn, DBUS_TYPE_UNIX_FD)) g_error ("right client connection claims it can send Unix fds"); if (dbus_connection_can_send_type (f->right_server_conn, DBUS_TYPE_UNIX_FD)) g_error ("right server connection claims it can send Unix fds"); } static void test_relay (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING /* We assume that any platform with working fd-passing is POSIX, * and therefore has open() and fstat() */ dbus_uint32_t serial; DBusMessage *outgoing, *incoming; int fd_after; struct stat stat_before; struct stat stat_after; test_connect (f, TRUE); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); if (!dbus_message_append_args (outgoing, DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); if (!dbus_connection_send (f->left_client_conn, outgoing, &serial)) oom ("sending message"); dbus_message_unref (outgoing); while (g_queue_get_length (&f->messages) < 1) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1); incoming = g_queue_pop_head (&f->messages); g_assert (dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (incoming), ==, DBUS_TYPE_UNIX_FD_AS_STRING); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial); if (!dbus_message_get_args (incoming, &f->e, DBUS_TYPE_UNIX_FD, &fd_after, DBUS_TYPE_INVALID)) g_error ("%s: %s", f->e.name, f->e.message); assert_no_error (&f->e); if (fstat (f->fd_before, &stat_before) < 0) g_error ("%s", g_strerror (errno)); if (fstat (fd_after, &stat_after) < 0) g_error ("%s", g_strerror (errno)); /* this seems like enough to say "it's the same file" */ g_assert_cmpint (stat_before.st_dev, ==, stat_after.st_dev); g_assert_cmpint (stat_before.st_ino, ==, stat_after.st_ino); g_assert_cmpint (stat_before.st_rdev, ==, stat_after.st_rdev); dbus_message_unref (incoming); if (close (fd_after) < 0) g_error ("%s", g_strerror (errno)); g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); g_assert (dbus_connection_get_is_connected (f->left_client_conn)); g_assert (dbus_connection_get_is_connected (f->left_server_conn)); #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void test_limit (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING dbus_uint32_t serial; DBusMessage *outgoing, *incoming; int i; test_connect (f, TRUE); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); for (i = 0; i < MAX_MESSAGE_UNIX_FDS; i++) { if (!dbus_message_append_args (outgoing, DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); } if (!dbus_connection_send (f->left_client_conn, outgoing, &serial)) oom ("sending message"); dbus_message_unref (outgoing); while (g_queue_get_length (&f->messages) < 1) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1); incoming = g_queue_pop_head (&f->messages); g_assert (dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial); dbus_message_unref (incoming); g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); g_assert (dbus_connection_get_is_connected (f->left_client_conn)); g_assert (dbus_connection_get_is_connected (f->left_server_conn)); #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void test_too_many (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING DBusMessage *outgoing; unsigned int i; test_connect (f, TRUE); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); for (i = 0; i < MAX_MESSAGE_UNIX_FDS + GPOINTER_TO_UINT (data); i++) { if (!dbus_message_append_args (outgoing, DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); } if (!dbus_connection_send (f->left_client_conn, outgoing, NULL)) oom ("sending message"); dbus_message_unref (outgoing); /* The sender is unceremoniously disconnected. */ while (dbus_connection_get_is_connected (f->left_client_conn) || dbus_connection_get_is_connected (f->left_server_conn)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } /* The message didn't get through without its fds. */ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0); /* The intended victim is unaffected by the left connection's * misbehaviour. */ g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void test_too_many_split (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING DBusMessage *outgoing; int i; DBusSocket left_client_socket; char *payload; int payload_len; DBusString buffer; int fds[TOO_MANY_FDS]; int done; /* This test deliberately pushes up against OS limits, so skip it * if we don't have enough fds. 4 times the maximum per message * ought to be enough: that will cover the message, the dup'd fds * we actually send, the copy that we potentially receive, and some * spare capacity for everything else. */ #ifdef HAVE_GETRLIMIT struct rlimit lim; if (getrlimit (RLIMIT_NOFILE, &lim) == 0) { if (lim.rlim_cur != RLIM_INFINITY && lim.rlim_cur < 4 * TOO_MANY_FDS) { g_test_skip ("not enough RLIMIT_NOFILE"); return; } } #endif test_connect (f, TRUE); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); /* TOO_MANY_FDS fds are far too many: in particular, Linux doesn't allow * sending this many in a single sendmsg(). libdbus never splits * a message between two sendmsg() calls if it can help it, and * in particular it always sends all the fds with the first sendmsg(), * but malicious senders might not be so considerate. */ for (i = 0; i < TOO_MANY_FDS; i++) { if (!dbus_message_append_args (outgoing, DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); } /* This probably shouldn't work for messages with fds, but it does, * which is convenient for this sort of trickery. */ if (!dbus_message_marshal (outgoing, &payload, &payload_len)) oom ("marshalling message"); _dbus_string_init_const_len (&buffer, payload, payload_len); for (i = 0; i < TOO_MANY_FDS; i++) { fds[i] = dup (f->fd_before); if (fds[i] < 0) g_error ("could not dup fd: %s", g_strerror (errno)); } /* This is blatant cheating, and the API documentation specifically * tells you not use this function in this way. Never do this * in application code. */ if (!dbus_connection_get_socket (f->left_client_conn, &left_client_socket.fd)) g_error ("'unix:' DBusConnection should have had a socket"); /* Just to be sure that we're at a message boundary. */ dbus_connection_flush (f->left_client_conn); /* We have too many fds for one sendmsg(), so send the first half * (rounding down if odd) with the first byte... */ done = _dbus_write_socket_with_unix_fds (left_client_socket, &buffer, 0, 1, &fds[0], TOO_MANY_FDS / 2); if (done < 0) g_error ("could not send first byte and first batch of fds: %s", g_strerror (errno)); /* ... and the second half (rounding up if odd) with the rest of * the message */ done = _dbus_write_socket_with_unix_fds (left_client_socket, &buffer, 1, payload_len - 1, &fds[TOO_MANY_FDS / 2], TOO_MANY_FDS - (TOO_MANY_FDS / 2)); if (done < 0) { g_error ("could not send rest of message and rest of fds: %s", g_strerror (errno)); } else if (done < payload_len - 1) { /* For simplicity, assume the socket buffer is big enough for the * whole message, which should be < 2 KiB. If this fails on some * OS, redo this test code to use a proper loop like the real * libdbus does. */ g_error ("short write in sendmsg(), fix this test: %d/%d", done, payload_len - 1); } dbus_free (payload); for (i = 0; i < TOO_MANY_FDS; i++) close (fds[i]); dbus_message_unref (outgoing); /* The sender is unceremoniously disconnected. */ while (dbus_connection_get_is_connected (f->left_client_conn) || dbus_connection_get_is_connected (f->left_server_conn)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } /* The message didn't get through without its fds. */ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0); /* The intended victim is unaffected by the left connection's * misbehaviour. */ g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void test_flood (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING unsigned int i, j; DBusMessage *outgoing[SOME_MESSAGES]; dbus_uint32_t serial; test_connect (f, TRUE); for (j = 0; j < SOME_MESSAGES; j++) { outgoing[j] = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing[j] != NULL); for (i = 0; i < GPOINTER_TO_UINT (data); i++) { if (!dbus_message_append_args (outgoing[j], DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); } } /* This is in its own loop so we do it as fast as possible */ for (j = 0; j < SOME_MESSAGES; j++) { if (!dbus_connection_send (f->left_client_conn, outgoing[j], &serial)) oom ("sending message"); } for (j = 0; j < SOME_MESSAGES; j++) { dbus_message_unref (outgoing[j]); } while (g_queue_get_length (&f->messages) < SOME_MESSAGES) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->messages), ==, SOME_MESSAGES); for (j = 0; j < SOME_MESSAGES; j++) { DBusMessage *incoming; incoming = g_queue_pop_head (&f->messages); g_assert (dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); dbus_message_unref (incoming); } g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); g_assert (dbus_connection_get_is_connected (f->left_client_conn)); g_assert (dbus_connection_get_is_connected (f->left_server_conn)); #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void test_odd_limit (Fixture *f, gconstpointer data) { #ifdef HAVE_UNIX_FD_PASSING DBusMessage *outgoing; int i; test_connect (f, TRUE); dbus_connection_set_max_message_unix_fds (f->left_server_conn, 7); dbus_connection_set_max_message_unix_fds (f->right_server_conn, 7); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); for (i = 0; i < 7 + GPOINTER_TO_INT (data); i++) { if (!dbus_message_append_args (outgoing, DBUS_TYPE_UNIX_FD, &f->fd_before, DBUS_TYPE_INVALID)) oom ("appending fd"); } if (!dbus_connection_send (f->left_client_conn, outgoing, NULL)) oom ("sending message"); dbus_message_unref (outgoing); if (GPOINTER_TO_INT (data) > 0) { /* The sender is unceremoniously disconnected. */ while (dbus_connection_get_is_connected (f->left_client_conn) || dbus_connection_get_is_connected (f->left_server_conn)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } /* The message didn't get through without its fds. */ g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 0); /* The intended victim is unaffected by the left connection's * misbehaviour. */ g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); } else { DBusMessage *incoming; /* We're at or under the limit. The message gets through intact. */ while (g_queue_get_length (&f->messages) < 1) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 1); incoming = g_queue_pop_head (&f->messages); g_assert (dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); dbus_message_unref (incoming); g_assert (dbus_connection_get_is_connected (f->right_client_conn)); g_assert (dbus_connection_get_is_connected (f->right_server_conn)); g_assert (dbus_connection_get_is_connected (f->left_client_conn)); g_assert (dbus_connection_get_is_connected (f->left_server_conn)); } #else g_test_skip ("fd-passing not supported on this platform"); #endif } static void teardown (Fixture *f, gconstpointer data G_GNUC_UNUSED) { if (f->left_client_conn != NULL) { dbus_connection_close (f->left_client_conn); dbus_connection_unref (f->left_client_conn); f->left_client_conn = NULL; } if (f->right_client_conn != NULL) { dbus_connection_close (f->right_client_conn); dbus_connection_unref (f->right_client_conn); f->right_client_conn = NULL; } if (f->left_server_conn != NULL) { dbus_connection_close (f->left_server_conn); dbus_connection_unref (f->left_server_conn); f->left_server_conn = NULL; } if (f->right_server_conn != NULL) { dbus_connection_close (f->right_server_conn); dbus_connection_unref (f->right_server_conn); f->right_server_conn = NULL; } if (f->server != NULL) { dbus_server_disconnect (f->server); dbus_server_unref (f->server); f->server = NULL; } if (f->ctx != NULL) test_main_context_unref (f->ctx); #ifdef HAVE_UNIX_FD_PASSING if (f->fd_before >= 0 && close (f->fd_before) < 0) g_error ("%s", g_strerror (errno)); #endif } int main (int argc, char **argv) { test_init (&argc, &argv); #ifdef HAVE_GETRLIMIT { struct rlimit lim; if (getrlimit (RLIMIT_NOFILE, &lim) < 0) g_error ("Failed to get RLIMIT_NOFILE limit: %s", g_strerror (errno)); if (lim.rlim_cur != RLIM_INFINITY && /* only run if we have a fairly generous margin of error * for stdout, stderr, duplicates, the D-Bus connection, etc. */ lim.rlim_cur < 2 * MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES) { g_message ("not enough RLIMIT_NOFILE to run this test"); /* Autotools exit code for "all skipped" */ return 77; } } #endif g_test_add ("/unsupported", Fixture, NULL, setup_unsupported, test_unsupported, teardown); g_test_add ("/relay", Fixture, NULL, setup, test_relay, teardown); g_test_add ("/limit", Fixture, NULL, setup, test_limit, teardown); g_test_add ("/too-many/plus1", Fixture, GUINT_TO_POINTER (1), setup, test_too_many, teardown); g_test_add ("/too-many/plus2", Fixture, GUINT_TO_POINTER (2), setup, test_too_many, teardown); g_test_add ("/too-many/plus17", Fixture, GUINT_TO_POINTER (17), setup, test_too_many, teardown); g_test_add ("/too-many/split", Fixture, NULL, setup, test_too_many_split, teardown); g_test_add ("/flood/1", Fixture, GUINT_TO_POINTER (1), setup, test_flood, teardown); #if MAX_MESSAGE_UNIX_FDS >= 2 g_test_add ("/flood/half-limit", Fixture, GUINT_TO_POINTER (MAX_MESSAGE_UNIX_FDS / 2), setup, test_flood, teardown); #endif #if MAX_MESSAGE_UNIX_FDS >= 4 g_test_add ("/flood/over-half-limit", Fixture, GUINT_TO_POINTER (3 * MAX_MESSAGE_UNIX_FDS / 4), setup, test_flood, teardown); #endif g_test_add ("/flood/limit", Fixture, GUINT_TO_POINTER (MAX_MESSAGE_UNIX_FDS), setup, test_flood, teardown); g_test_add ("/odd-limit/minus1", Fixture, GINT_TO_POINTER (-1), setup, test_odd_limit, teardown); g_test_add ("/odd-limit/at", Fixture, GINT_TO_POINTER (0), setup, test_odd_limit, teardown); g_test_add ("/odd-limit/plus1", Fixture, GINT_TO_POINTER (+1), setup, test_odd_limit, teardown); g_test_add ("/odd-limit/plus2", Fixture, GINT_TO_POINTER (+2), setup, test_odd_limit, teardown); return g_test_run (); } dbus-1.10.6/test/test-exit.c0000644000175000017500000000020312602773110015601 0ustar00smcvsmcv00000000000000#include "config.h" /* This is a process that just exits with a failure code */ int main (int argc, char **argv) { return 1; } dbus-1.10.6/test/dbus-daemon-eavesdrop.c0000644000175000017500000002773012602773110020055 0ustar00smcvsmcv00000000000000/* Integration tests for the eavesdrop=true|false keyword in DBusMatchRule * * Author: Cosimo Alfarano * Based on: tests/dbus-daemon.c by Simon McVittie * Copyright © 2010-2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "test-utils-glib.h" #define SENDER_NAME "test.eavesdrop.sender" #define SENDER_PATH "/test/eavesdrop/sender" #define SENDER_IFACE SENDER_NAME #define SENDER_SIGNAL_NAME "Signal" #define SENDER_STOPPER_NAME "Stopper" /* This rule is equivalent to the one added to a proxy connecting to * SENDER_NAME+SENDER_IFACE, plus restricting on signal name. * Being more restrictive, if the connection receives what we need, for sure * the original proxy rule will match it */ #define RECEIVER_RULE "sender='" SENDER_NAME "'," \ "interface='" SENDER_IFACE "'," \ "type='signal'," \ "member='" SENDER_SIGNAL_NAME "'" #define POLITELISTENER_RULE RECEIVER_RULE #define EAVESDROPPER_RULE RECEIVER_RULE ",eavesdrop=true" #define STOPPER_RULE "sender='" SENDER_NAME \ "',interface='" SENDER_IFACE "',type='signal',member='" SENDER_STOPPER_NAME "'" /* a connection received a signal to whom? */ typedef enum { NONE_YET = 0, TO_ME, TO_OTHER, BROADCAST, } SignalDst; typedef struct { TestMainContext *ctx; DBusError e; GError *ge; GPid daemon_pid; /* eavedrop keyword tests */ DBusConnection *sender; DBusConnection *receiver; SignalDst receiver_dst; dbus_bool_t receiver_got_stopper; DBusConnection *eavesdropper; SignalDst eavesdropper_dst; dbus_bool_t eavesdropper_got_stopper; DBusConnection *politelistener; SignalDst politelistener_dst; dbus_bool_t politelistener_got_stopper; } Fixture; /* send a unicast signal to to ensure that no other connection * listening is the actual recipient for the signal */ static DBusHandlerResult sender_send_unicast_to_sender (Fixture *f) { DBusMessage *signal; signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_SIGNAL_NAME); dbus_message_set_destination (signal, dbus_bus_get_unique_name (f->sender)); if (signal == NULL) g_error ("OOM"); if (!dbus_connection_send (f->sender, signal, NULL)) g_error ("OOM"); dbus_message_unref (signal); return DBUS_HANDLER_RESULT_HANDLED; } /* send a unicast signal to , making and * not a actual recipient for it */ static DBusHandlerResult sender_send_unicast_to_receiver (Fixture *f) { DBusMessage *signal; signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_SIGNAL_NAME); dbus_message_set_destination (signal, dbus_bus_get_unique_name (f->receiver)); if (signal == NULL) g_error ("OOM"); if (!dbus_connection_send (f->sender, signal, NULL)) g_error ("OOM"); dbus_message_unref (signal); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult sender_send_broadcast (Fixture *f) { DBusMessage *signal; signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_SIGNAL_NAME); dbus_message_set_destination (signal, NULL); if (signal == NULL) g_error ("OOM"); if (!dbus_connection_send (f->sender, signal, NULL)) g_error ("OOM"); dbus_message_unref (signal); return DBUS_HANDLER_RESULT_HANDLED; } /* Send special broadcast signal to indicate that the connections can "stop" * listening and check their results. * DBus does not re-order messages, so when the three connections have received * this signal, we are sure that any message sent before it has also been * dispatched. */ static DBusHandlerResult sender_send_stopper (Fixture *f) { DBusMessage *signal; signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_STOPPER_NAME); dbus_message_set_destination (signal, NULL); if (signal == NULL) g_error ("OOM"); if (!dbus_connection_send (f->sender, signal, NULL)) g_error ("OOM"); dbus_message_unref (signal); return DBUS_HANDLER_RESULT_HANDLED; } /* Ignore NameAcquired, then depending on the signal received: * - updates f->_dst based on the destination of the message * - asserts that received the stop signal */ static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; SignalDst *dst = NULL; DBusConnection **conn; dbus_bool_t *got_stopper; if (0 == strcmp (dbus_message_get_member (message), "NameAcquired")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (connection == f->receiver) { dst = &(f->receiver_dst); conn = &(f->receiver); got_stopper = &(f->receiver_got_stopper); } else if (connection == f->eavesdropper) { dst = &(f->eavesdropper_dst); conn = &(f->eavesdropper); got_stopper = &(f->eavesdropper_got_stopper); } else if (connection == f->politelistener) { dst = &(f->politelistener_dst); conn = &(f->politelistener); got_stopper = &(f->politelistener_got_stopper); } else { g_error ("connection not matching"); } if (0 == strcmp (dbus_message_get_member (message), SENDER_SIGNAL_NAME)) { if (dbus_message_get_destination (message) == NULL) *dst = BROADCAST; else if (0 == strcmp (dbus_message_get_destination (message), dbus_bus_get_unique_name (*conn))) *dst = TO_ME; else /* if (dbus_message_get_destination (message) != NULL) */ *dst = TO_OTHER; } else if (0 == strcmp (dbus_message_get_member (message), SENDER_STOPPER_NAME)) { *got_stopper = TRUE; } else { g_error ("got unknown member from message: %s", dbus_message_get_member (message)); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void add_receiver_filter (Fixture *f) { DBusError e = DBUS_ERROR_INIT; dbus_bus_add_match (f->receiver, RECEIVER_RULE, &e); test_assert_no_error (&e); dbus_bus_add_match (f->receiver, STOPPER_RULE, &e); test_assert_no_error (&e); if (!dbus_connection_add_filter (f->receiver, signal_filter, f, NULL)) g_error ("OOM"); } static void add_eavesdropper_filter (Fixture *f) { DBusError e = DBUS_ERROR_INIT; dbus_bus_add_match (f->eavesdropper, EAVESDROPPER_RULE, &e); test_assert_no_error (&e); dbus_bus_add_match (f->eavesdropper, STOPPER_RULE, &e); test_assert_no_error (&e); if (!dbus_connection_add_filter (f->eavesdropper, signal_filter, f, NULL)) g_error ("OOM"); } static void add_politelistener_filter (Fixture *f) { DBusError e = DBUS_ERROR_INIT; dbus_bus_add_match (f->politelistener, POLITELISTENER_RULE, &e); test_assert_no_error (&e); dbus_bus_add_match (f->politelistener, STOPPER_RULE, &e); test_assert_no_error (&e); if (!dbus_connection_add_filter (f->politelistener, signal_filter, f, NULL)) g_error ("OOM"); } static void setup (Fixture *f, gconstpointer context G_GNUC_UNUSED) { gchar *address; f->ctx = test_main_context_get (); f->ge = NULL; dbus_error_init (&f->e); address = test_get_dbus_daemon (NULL, TEST_USER_ME, &f->daemon_pid); f->sender = test_connect_to_bus (f->ctx, address); dbus_bus_request_name (f->sender, SENDER_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &(f->e)); f->receiver = test_connect_to_bus (f->ctx, address); f->eavesdropper = test_connect_to_bus (f->ctx, address); f->politelistener = test_connect_to_bus (f->ctx, address); add_receiver_filter (f); add_politelistener_filter (f); add_eavesdropper_filter (f); g_free (address); } static void test_eavesdrop_broadcast (Fixture *f, gconstpointer context G_GNUC_UNUSED) { sender_send_broadcast (f); sender_send_stopper (f); while (!f->receiver_got_stopper || !f->politelistener_got_stopper || !f->eavesdropper_got_stopper) test_main_context_iterate (f->ctx, TRUE); /* all the three connection can receive a broadcast */ g_assert_cmpint (f->receiver_dst, ==, BROADCAST); g_assert_cmpint (f->politelistener_dst, ==, BROADCAST); g_assert_cmpint (f->eavesdropper_dst, ==, BROADCAST); } /* a way to say that none of the listening connection are destination of the * signal */ static void test_eavesdrop_unicast_to_sender (Fixture *f, gconstpointer context G_GNUC_UNUSED) { sender_send_unicast_to_sender (f); sender_send_stopper (f); while (!f->receiver_got_stopper || !f->politelistener_got_stopper || !f->eavesdropper_got_stopper) test_main_context_iterate (f->ctx, TRUE); /* not directed to it and not broadcasted, they cannot receive it */ g_assert_cmpint (f->receiver_dst, ==, NONE_YET); g_assert_cmpint (f->politelistener_dst, ==, NONE_YET); /* eavesdrop=true, it will receive the signal even though it's not directed * to it */ g_assert_cmpint (f->eavesdropper_dst, ==, TO_OTHER); } static void test_eavesdrop_unicast_to_receiver (Fixture *f, gconstpointer context G_GNUC_UNUSED) { sender_send_unicast_to_receiver (f); sender_send_stopper (f); while (!f->receiver_got_stopper || !f->politelistener_got_stopper || !f->eavesdropper_got_stopper) test_main_context_iterate (f->ctx, TRUE); /* direct to him */ g_assert_cmpint (f->receiver_dst, ==, TO_ME); /* not directed to it and not broadcasted, it cannot receive it */ g_assert_cmpint (f->politelistener_dst, ==, NONE_YET); /* eavesdrop=true, it will receive the signal even though it's not directed * to it */ g_assert_cmpint (f->eavesdropper_dst, ==, TO_OTHER); } static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { dbus_error_free (&f->e); g_clear_error (&f->ge); if (f->sender != NULL) { dbus_connection_close (f->sender); dbus_connection_unref (f->sender); f->sender = NULL; } if (f->receiver != NULL) { dbus_connection_remove_filter (f->receiver, signal_filter, f); dbus_connection_close (f->receiver); dbus_connection_unref (f->receiver); f->receiver = NULL; } if (f->politelistener != NULL) { dbus_connection_remove_filter (f->politelistener, signal_filter, f); dbus_connection_close (f->politelistener); dbus_connection_unref (f->politelistener); f->politelistener = NULL; } if (f->eavesdropper != NULL) { dbus_connection_remove_filter (f->eavesdropper, signal_filter, f); dbus_connection_close (f->eavesdropper); dbus_connection_unref (f->eavesdropper); f->eavesdropper = NULL; } test_kill_pid (f->daemon_pid); g_spawn_close_pid (f->daemon_pid); test_main_context_unref (f->ctx); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/eavedrop/match_keyword/broadcast", Fixture, NULL, setup, test_eavesdrop_broadcast, teardown); g_test_add ("/eavedrop/match_keyword/unicast_to_receiver", Fixture, NULL, setup, test_eavesdrop_unicast_to_receiver, teardown); g_test_add ("/eavedrop/match_keyword/unicast_to_sender", Fixture, NULL, setup, test_eavesdrop_unicast_to_sender, teardown); return g_test_run (); } dbus-1.10.6/test/dbus-daemon.c0000644000175000017500000005101212602773110016055 0ustar00smcvsmcv00000000000000/* Integration tests for the dbus-daemon * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * Copyright © 2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include "test-utils-glib.h" #include #ifdef DBUS_UNIX # include # include #endif /* Platforms where we know that credentials-passing passes both the * uid and the pid. Please keep these in alphabetical order. * * These platforms should #error in _dbus_read_credentials_socket() * if we didn't detect their flavour of credentials-passing, since that * would be a regression. */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__linux__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) # define UNIX_USER_SHOULD_WORK # define PID_SHOULD_WORK #endif /* Platforms where we know that credentials-passing passes the * uid, but not necessarily the pid. Again, alphabetical order please. * * These platforms should also #error in _dbus_read_credentials_socket() * if we didn't detect their flavour of credentials-passing. */ #if 0 /* defined(__your_platform_here__) */ # define UNIX_USER_SHOULD_WORK #endif typedef struct { gboolean skip; TestMainContext *ctx; DBusError e; GError *ge; GPid daemon_pid; DBusConnection *left_conn; DBusConnection *right_conn; gboolean right_conn_echo; gboolean wait_forever_called; gchar *tmp_runtime_dir; gchar *saved_runtime_dir; } Fixture; static DBusHandlerResult echo_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { Fixture *f = user_data; DBusMessage *reply; if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* WaitForever() never replies, emulating a service that has got stuck */ if (dbus_message_is_method_call (message, "com.example", "WaitForever")) { f->wait_forever_called = TRUE; return DBUS_HANDLER_RESULT_HANDLED; } reply = dbus_message_new_method_return (message); if (reply == NULL) g_error ("OOM"); if (!dbus_connection_send (connection, reply, NULL)) g_error ("OOM"); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } typedef struct { const char *bug_ref; guint min_messages; const char *config_file; enum { SPECIFY_ADDRESS = 0, RELY_ON_DEFAULT } connect_mode; } Config; static void setup (Fixture *f, gconstpointer context) { const Config *config = context; gchar *address; f->ctx = test_main_context_get (); f->ge = NULL; dbus_error_init (&f->e); if (config != NULL && config->connect_mode == RELY_ON_DEFAULT) { /* this is chosen to be something needing escaping */ f->tmp_runtime_dir = g_dir_make_tmp ("dbus=daemon=test.XXXXXX", &f->ge); g_assert_no_error (f->ge); /* we're relying on being single-threaded for this to be safe */ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR")); g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE); } address = test_get_dbus_daemon (config ? config->config_file : NULL, TEST_USER_ME, &f->daemon_pid); if (address == NULL) { f->skip = TRUE; return; } f->left_conn = test_connect_to_bus (f->ctx, address); if (config != NULL && config->connect_mode == RELY_ON_DEFAULT) { /* use the default bus for the echo service ("right"), to check that * it ends up on the same bus as the client ("left") */ f->right_conn = dbus_bus_get_private (DBUS_BUS_SESSION, &f->e); test_assert_no_error (&f->e); if (!test_connection_setup (f->ctx, f->right_conn)) g_error ("OOM"); } else { f->right_conn = test_connect_to_bus (f->ctx, address); } g_free (address); } static void add_echo_filter (Fixture *f) { if (!dbus_connection_add_filter (f->right_conn, echo_filter, f, NULL)) g_error ("OOM"); f->right_conn_echo = TRUE; } static void pc_count (DBusPendingCall *pc, void *data) { guint *received_p = data; (*received_p)++; } static void test_echo (Fixture *f, gconstpointer context) { const Config *config = context; guint count = 2000; guint sent; guint received = 0; double elapsed; if (f->skip) return; if (config != NULL && config->bug_ref != NULL) g_test_bug (config->bug_ref); if (g_test_perf ()) count = 100000; if (config != NULL) count = MAX (config->min_messages, count); add_echo_filter (f); g_test_timer_start (); for (sent = 0; sent < count; sent++) { DBusMessage *m = dbus_message_new_method_call ( dbus_bus_get_unique_name (f->right_conn), "/", "com.example", "Spam"); DBusPendingCall *pc; if (m == NULL) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_INFINITE) || pc == NULL) g_error ("OOM"); if (dbus_pending_call_get_completed (pc)) pc_count (pc, &received); else if (!dbus_pending_call_set_notify (pc, pc_count, &received, NULL)) g_error ("OOM"); dbus_pending_call_unref (pc); dbus_message_unref (m); } while (received < count) test_main_context_iterate (f->ctx, TRUE); elapsed = g_test_timer_elapsed (); g_test_maximized_result (count / elapsed, "%u messages / %f seconds", count, elapsed); } static void test_no_reply (Fixture *f, gconstpointer context) { const Config *config = context; DBusMessage *m; DBusPendingCall *pc; DBusMessage *reply = NULL; enum { TIMEOUT, DISCONNECT } mode; gboolean ok; if (f->skip) return; g_test_bug ("76112"); if (config != NULL && config->config_file != NULL) mode = TIMEOUT; else mode = DISCONNECT; m = dbus_message_new_method_call ( dbus_bus_get_unique_name (f->right_conn), "/", "com.example", "WaitForever"); add_echo_filter (f); if (m == NULL) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_INFINITE) || pc == NULL) g_error ("OOM"); if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &reply); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &reply, NULL)) g_error ("OOM"); dbus_pending_call_unref (pc); dbus_message_unref (m); if (mode == DISCONNECT) { while (!f->wait_forever_called) test_main_context_iterate (f->ctx, TRUE); dbus_connection_remove_filter (f->right_conn, echo_filter, f); dbus_connection_close (f->right_conn); dbus_connection_unref (f->right_conn); f->right_conn = NULL; } while (reply == NULL) test_main_context_iterate (f->ctx, TRUE); /* using inefficient string comparison for better assertion message */ g_assert_cmpstr ( dbus_message_type_to_string (dbus_message_get_type (reply)), ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR)); ok = dbus_set_error_from_message (&f->e, reply); g_assert (ok); g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY); if (mode == DISCONNECT) g_assert_cmpstr (f->e.message, ==, "Message recipient disconnected from message bus without replying"); else g_assert_cmpstr (f->e.message, ==, "Message did not receive a reply (timeout by message bus)"); } static void test_creds (Fixture *f, gconstpointer context) { const char *unique = dbus_bus_get_unique_name (f->left_conn); DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionCredentials"); DBusPendingCall *pc; DBusMessageIter args_iter; DBusMessageIter arr_iter; DBusMessageIter pair_iter; DBusMessageIter var_iter; enum { SEEN_UNIX_USER = 1, SEEN_PID = 2, SEEN_WINDOWS_SID = 4, SEEN_LINUX_SECURITY_LABEL = 8 } seen = 0; if (m == NULL) g_error ("OOM"); if (!dbus_message_append_args (m, DBUS_TYPE_STRING, &unique, DBUS_TYPE_INVALID)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); g_assert_cmpstr (dbus_message_get_signature (m), ==, "a{sv}"); dbus_message_iter_init (m, &args_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, DBUS_TYPE_ARRAY); g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==, DBUS_TYPE_DICT_ENTRY); dbus_message_iter_recurse (&args_iter, &arr_iter); while (dbus_message_iter_get_arg_type (&arr_iter) != DBUS_TYPE_INVALID) { const char *name; dbus_message_iter_recurse (&arr_iter, &pair_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&pair_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_get_basic (&pair_iter, &name); dbus_message_iter_next (&pair_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&pair_iter), ==, DBUS_TYPE_VARIANT); dbus_message_iter_recurse (&pair_iter, &var_iter); if (g_strcmp0 (name, "UnixUserID") == 0) { #ifdef G_OS_UNIX guint32 u32; g_assert (!(seen & SEEN_UNIX_USER)); g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, DBUS_TYPE_UINT32); dbus_message_iter_get_basic (&var_iter, &u32); g_test_message ("%s of this process is %u", name, u32); g_assert_cmpuint (u32, ==, geteuid ()); seen |= SEEN_UNIX_USER; #else g_assert_not_reached (); #endif } else if (g_strcmp0 (name, "WindowsSID") == 0) { #ifdef G_OS_WIN32 gchar *sid; char *self_sid; g_assert (!(seen & SEEN_WINDOWS_SID)); g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, DBUS_TYPE_STRING); dbus_message_iter_get_basic (&var_iter, &sid); g_test_message ("%s of this process is %s", name, sid); if (_dbus_getsid (&self_sid, 0)) { g_assert_cmpstr (self_sid, ==, sid); LocalFree(self_sid); } seen |= SEEN_WINDOWS_SID; #else g_assert_not_reached (); #endif } else if (g_strcmp0 (name, "ProcessID") == 0) { guint32 u32; g_assert (!(seen & SEEN_PID)); g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, DBUS_TYPE_UINT32); dbus_message_iter_get_basic (&var_iter, &u32); g_test_message ("%s of this process is %u", name, u32); #ifdef G_OS_UNIX g_assert_cmpuint (u32, ==, getpid ()); #elif defined(G_OS_WIN32) g_assert_cmpuint (u32, ==, GetCurrentProcessId ()); #else g_assert_not_reached (); #endif seen |= SEEN_PID; } else if (g_strcmp0 (name, "LinuxSecurityLabel") == 0) { #ifdef __linux__ gchar *label; int len; DBusMessageIter ay_iter; g_assert (!(seen & SEEN_LINUX_SECURITY_LABEL)); g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, DBUS_TYPE_ARRAY); dbus_message_iter_recurse (&var_iter, &ay_iter); g_assert_cmpuint (dbus_message_iter_get_arg_type (&ay_iter), ==, DBUS_TYPE_BYTE); dbus_message_iter_get_fixed_array (&ay_iter, &label, &len); g_test_message ("%s of this process is %s", name, label); g_assert_cmpuint (strlen (label) + 1, ==, len); seen |= SEEN_LINUX_SECURITY_LABEL; #else g_assert_not_reached (); #endif } dbus_message_iter_next (&arr_iter); } #ifdef UNIX_USER_SHOULD_WORK g_assert (seen & SEEN_UNIX_USER); #endif #ifdef PID_SHOULD_WORK g_assert (seen & SEEN_PID); #endif #ifdef G_OS_WIN32 g_assert (seen & SEEN_WINDOWS_SID); #endif } static void test_processid (Fixture *f, gconstpointer context) { const char *unique = dbus_bus_get_unique_name (f->left_conn); DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixProcessID"); DBusPendingCall *pc; DBusError error = DBUS_ERROR_INIT; guint32 pid; if (m == NULL) g_error ("OOM"); if (!dbus_message_append_args (m, DBUS_TYPE_STRING, &unique, DBUS_TYPE_INVALID)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); if (dbus_message_get_args (m, &error, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) { g_assert_cmpstr (dbus_message_get_signature (m), ==, "u"); test_assert_no_error (&error); g_test_message ("GetConnectionUnixProcessID returned %u", pid); #ifdef G_OS_UNIX g_assert_cmpuint (pid, ==, getpid ()); #elif defined(G_OS_WIN32) g_assert_cmpuint (pid, ==, GetCurrentProcessId ()); #else g_assert_not_reached (); #endif } else { g_assert_cmpstr (error.name, ==, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN); #ifdef PID_SHOULD_WORK g_error ("Expected pid to be passed, but got %s: %s", error.name, error.message); #endif dbus_error_free (&error); } } static void test_canonical_path_uae (Fixture *f, gconstpointer context) { DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment"); DBusPendingCall *pc; DBusMessageIter args_iter; DBusMessageIter arr_iter; if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); /* Append an empty a{ss} (string => string dictionary). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "{ss}", &arr_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); /* it succeeds */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_unref (m); /* Now try with the wrong object path */ m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, "/com/example/Wrong", DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment"); if (m == NULL) g_error ("OOM"); dbus_message_iter_init_append (m, &args_iter); /* Append an empty a{ss} (string => string dictionary). */ if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY, "{ss}", &arr_iter) || !dbus_message_iter_close_container (&args_iter, &arr_iter)) g_error ("OOM"); if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL) g_error ("OOM"); dbus_message_unref (m); m = NULL; if (dbus_pending_call_get_completed (pc)) test_pending_call_store_reply (pc, &m); else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply, &m, NULL)) g_error ("OOM"); while (m == NULL) test_main_context_iterate (f->ctx, TRUE); /* it fails, yielding an error message with one string argument */ g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR); g_assert_cmpstr (dbus_message_get_error_name (m), ==, DBUS_ERROR_ACCESS_DENIED); g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); dbus_message_unref (m); } static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { dbus_error_free (&f->e); g_clear_error (&f->ge); if (f->left_conn != NULL) { dbus_connection_close (f->left_conn); dbus_connection_unref (f->left_conn); f->left_conn = NULL; } if (f->right_conn != NULL) { if (f->right_conn_echo) { dbus_connection_remove_filter (f->right_conn, echo_filter, f); f->right_conn_echo = FALSE; } dbus_connection_close (f->right_conn); dbus_connection_unref (f->right_conn); f->right_conn = NULL; } if (f->daemon_pid != 0) { test_kill_pid (f->daemon_pid); g_spawn_close_pid (f->daemon_pid); f->daemon_pid = 0; } if (f->tmp_runtime_dir != NULL) { gchar *path; /* the socket may exist */ path = g_strdup_printf ("%s/bus", f->tmp_runtime_dir); g_assert (g_remove (path) == 0 || errno == ENOENT); g_free (path); /* there shouldn't be anything else in there */ g_assert_cmpint (g_rmdir (f->tmp_runtime_dir), ==, 0); /* we're relying on being single-threaded for this to be safe */ if (f->saved_runtime_dir != NULL) g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE); else g_unsetenv ("XDG_RUNTIME_DIR"); g_free (f->saved_runtime_dir); g_free (f->tmp_runtime_dir); } test_main_context_unref (f->ctx); } static Config limited_config = { "34393", 10000, "valid-config-files/incoming-limit.conf", SPECIFY_ADDRESS }; static Config finite_timeout_config = { NULL, 1, "valid-config-files/finite-timeout.conf", SPECIFY_ADDRESS }; #ifdef DBUS_UNIX static Config listen_unix_runtime_config = { "61303", 1, "valid-config-files/listen-unix-runtime.conf", RELY_ON_DEFAULT }; #endif int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown); g_test_add ("/echo/limited", Fixture, &limited_config, setup, test_echo, teardown); g_test_add ("/no-reply/disconnect", Fixture, NULL, setup, test_no_reply, teardown); g_test_add ("/no-reply/timeout", Fixture, &finite_timeout_config, setup, test_no_reply, teardown); g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown); g_test_add ("/processid", Fixture, NULL, setup, test_processid, teardown); g_test_add ("/canonical-path/uae", Fixture, NULL, setup, test_canonical_path_uae, teardown); #ifdef DBUS_UNIX /* We can't test this in loopback.c with the rest of unix:runtime=yes, * because dbus_bus_get[_private] is the only way to use the default, * and that blocks on a round-trip to the dbus-daemon */ g_test_add ("/unix-runtime-is-default", Fixture, &listen_unix_runtime_config, setup, test_echo, teardown); #endif return g_test_run (); } dbus-1.10.6/test/corrupt.c0000644000175000017500000002630412602773110015363 0ustar00smcvsmcv00000000000000/* Regression test for being disconnected by a corrupt message (fd.o #15578) * * Author: Simon McVittie * Copyright © 2010-2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include "test-utils-glib.h" typedef struct { DBusError e; TestMainContext *ctx; DBusServer *server; DBusConnection *server_conn; /* queue of DBusMessage */ GQueue client_messages; DBusConnection *client_conn; } Fixture; static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static DBusHandlerResult client_message_cb (DBusConnection *client_conn, DBusMessage *message, void *data) { Fixture *f = data; g_assert (client_conn == f->client_conn); g_queue_push_tail (&f->client_messages, dbus_message_ref (message)); return DBUS_HANDLER_RESULT_HANDLED; } static void new_conn_cb (DBusServer *server, DBusConnection *server_conn, void *data) { Fixture *f = data; g_assert (f->server_conn == NULL); f->server_conn = dbus_connection_ref (server_conn); test_connection_setup (f->ctx, server_conn); } static void setup (Fixture *f, gconstpointer addr) { f->ctx = test_main_context_get (); dbus_error_init (&f->e); g_queue_init (&f->client_messages); f->server = dbus_server_listen (addr, &f->e); assert_no_error (&f->e); g_assert (f->server != NULL); dbus_server_set_new_connection_function (f->server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->server); } static void test_connect (Fixture *f, gconstpointer addr G_GNUC_UNUSED) { dbus_bool_t have_mem; g_assert (f->server_conn == NULL); f->client_conn = dbus_connection_open_private ( dbus_server_get_address (f->server), &f->e); assert_no_error (&f->e); g_assert (f->client_conn != NULL); test_connection_setup (f->ctx, f->client_conn); while (f->server_conn == NULL) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } have_mem = dbus_connection_add_filter (f->client_conn, client_message_cb, f, NULL); g_assert (have_mem); } static void test_message (Fixture *f, gconstpointer addr) { dbus_bool_t have_mem; dbus_uint32_t serial; DBusMessage *outgoing, *incoming; test_connect (f, addr); outgoing = dbus_message_new_signal ("/com/example/Hello", "com.example.Hello", "Greeting"); g_assert (outgoing != NULL); have_mem = dbus_connection_send (f->server_conn, outgoing, &serial); g_assert (have_mem); g_assert (serial != 0); while (g_queue_is_empty (&f->client_messages)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } g_assert_cmpuint (g_queue_get_length (&f->client_messages), ==, 1); incoming = g_queue_pop_head (&f->client_messages); g_assert (!dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "com.example.Hello"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (incoming), ==, ""); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello"); g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial); dbus_message_unref (incoming); dbus_message_unref (outgoing); } static void send_n_bytes (GSocket *socket, const gchar *blob, gssize blob_len) { gssize len, total_sent; GError *gerror = NULL; total_sent = 0; while (total_sent < blob_len) { len = g_socket_send (socket, blob + total_sent, blob_len - total_sent, NULL, &gerror); /* this is NULL-safe: a NULL error does not match */ if (g_error_matches (gerror, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { /* we could wait for G_IO_OUT, but life's too short; just sleep */ g_clear_error (&gerror); g_usleep (G_USEC_PER_SEC / 10); continue; } g_assert_no_error (gerror); g_assert (len >= 0); total_sent += len; } } /* Enough bytes for it to be obvious that this connection is broken */ #define CORRUPT_LEN 1024 /* All-zero is not a valid D-Bus message header - for a start, this is * protocol version 1, not 0 */ static const gchar not_a_dbus_message[CORRUPT_LEN] = { 0 }; static void test_corrupt (Fixture *f, gconstpointer addr) { GSocket *socket; GError *gerror = NULL; int fd; DBusMessage *incoming; test_message (f, addr); dbus_connection_flush (f->server_conn); /* OK, now the connection is working, let's break it! Don't try this * at home; splicing arbitrary bytes into the middle of the stream is * specifically documented as not a valid thing to do. Who'd have thought? */ if (!dbus_connection_get_socket (f->server_conn, &fd)) g_error ("failed to steal fd from server connection"); socket = g_socket_new_from_fd (fd, &gerror); g_assert_no_error (gerror); g_assert (socket != NULL); send_n_bytes (socket, not_a_dbus_message, CORRUPT_LEN); /* Now spin on the client connection: the server just sent it complete * rubbish, so it should disconnect */ while (g_queue_is_empty (&f->client_messages)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } incoming = g_queue_pop_head (&f->client_messages); g_assert (!dbus_message_contains_unix_fds (incoming)); g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (incoming), ==, "org.freedesktop.DBus.Local"); g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Disconnected"); g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (incoming), ==, ""); g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/org/freedesktop/DBus/Local"); dbus_message_unref (incoming); /* Free the DBusConnection before the GSocket, because GSocket is * going to close our fd. GSocket tolerates closing an already-closed * fd, whereas DBusLoop + DBusSocketSetEpoll doesn't. On Unix * we could use dup() but that isn't portable to Windows :-( */ dbus_connection_close (f->server_conn); dbus_connection_unref (f->server_conn); f->server_conn = NULL; g_object_unref (socket); } static void test_byte_order (Fixture *f, gconstpointer addr) { GSocket *socket; GError *gerror = NULL; int fd; char *blob; const gchar *arg = not_a_dbus_message; const gchar * const *args = &arg; int blob_len; DBusMessage *message; dbus_bool_t mem; test_message (f, addr); message = dbus_message_new_signal ("/", "a.b", "c"); g_assert (message != NULL); /* Append 0xFF bytes, so that the length of the body when byte-swapped * is 0xFF000000, which is invalid */ mem = dbus_message_append_args (message, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &args, 0xFF, DBUS_TYPE_INVALID); g_assert (mem); mem = dbus_message_marshal (message, &blob, &blob_len); g_assert (mem); g_assert_cmpuint (blob_len, >, 0xFF); g_assert (blob != NULL); dbus_message_unref (message); /* Break the message by changing its claimed byte order, without actually * byteswapping anything. We happen to know that byte order is the first * byte. */ if (blob[0] == 'B') blob[0] = 'l'; else blob[0] = 'B'; /* OK, now the connection is working, let's break it */ dbus_connection_flush (f->server_conn); if (!dbus_connection_get_socket (f->server_conn, &fd)) g_error ("failed to steal fd from server connection"); socket = g_socket_new_from_fd (fd, &gerror); g_assert_no_error (gerror); g_assert (socket != NULL); send_n_bytes (socket, blob, blob_len); dbus_free (blob); /* Now spin on the client connection: the server just sent it a faulty * message, so it should disconnect */ while (g_queue_is_empty (&f->client_messages)) { test_progress ('.'); test_main_context_iterate (f->ctx, TRUE); } message = g_queue_pop_head (&f->client_messages); g_assert (!dbus_message_contains_unix_fds (message)); g_assert_cmpstr (dbus_message_get_destination (message), ==, NULL); g_assert_cmpstr (dbus_message_get_error_name (message), ==, NULL); g_assert_cmpstr (dbus_message_get_interface (message), ==, "org.freedesktop.DBus.Local"); g_assert_cmpstr (dbus_message_get_member (message), ==, "Disconnected"); g_assert_cmpstr (dbus_message_get_sender (message), ==, NULL); g_assert_cmpstr (dbus_message_get_signature (message), ==, ""); g_assert_cmpstr (dbus_message_get_path (message), ==, "/org/freedesktop/DBus/Local"); dbus_message_unref (message); /* Free the DBusConnection before the GSocket, as above. */ dbus_connection_close (f->server_conn); dbus_connection_unref (f->server_conn); f->server_conn = NULL; g_object_unref (socket); } static void teardown (Fixture *f, gconstpointer addr G_GNUC_UNUSED) { if (f->client_conn != NULL) { dbus_connection_close (f->client_conn); dbus_connection_unref (f->client_conn); f->client_conn = NULL; } if (f->server_conn != NULL) { dbus_connection_close (f->server_conn); dbus_connection_unref (f->server_conn); f->server_conn = NULL; } if (f->server != NULL) { dbus_server_disconnect (f->server); dbus_server_unref (f->server); f->server = NULL; } test_main_context_unref (f->ctx); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_corrupt, teardown); #ifdef DBUS_UNIX g_test_add ("/corrupt/unix", Fixture, "unix:tmpdir=/tmp", setup, test_corrupt, teardown); #endif g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_byte_order, teardown); return g_test_run (); } dbus-1.10.6/test/manual-tcp.c0000644000175000017500000000167112602773110015726 0ustar00smcvsmcv00000000000000/* * Simple manual tcp check * * supports: * - server listening check * * syntax: manual-tcp [|] * */ #include "config.h" #include "dbus/dbus-server-socket.h" #include int main (int argc, char **argv) { DBusServer *server; DBusError error; int result = 0; int i; char *family = NULL; if (argc == 2) family = argv[1]; for (i = 0; i < 1000; i++) { dbus_error_init (&error); server = _dbus_server_new_for_tcp_socket ("localhost", "localhost", "0", family, &error, FALSE); if (server == NULL) { printf("%d: %s %s\n",i, error.name, error.message); dbus_error_free(&error); result = -1; } else { printf("%d: %s \n",i, dbus_server_get_address(server)); dbus_server_disconnect(server); dbus_server_unref(server); } } return result; } dbus-1.10.6/test/manual-paths.c0000644000175000017500000000273312624705346016271 0ustar00smcvsmcv00000000000000/* * Simple manual paths check * * syntax: manual-paths * */ #include "config.h" #include "dbus/dbus-list.h" #include "dbus/dbus-internals.h" #include "dbus/dbus-sysdeps.h" #include static dbus_bool_t print_install_root() { char runtime_prefix[1000]; if (!_dbus_get_install_root(runtime_prefix, sizeof(runtime_prefix))) { fprintf(stderr, "dbus_get_install_root() failed\n"); return FALSE; } fprintf(stdout, "dbus_get_install_root() returned '%s'\n", runtime_prefix); return TRUE; } static dbus_bool_t print_service_dirs() { DBusList *dirs; DBusList *link; dirs = NULL; if (!_dbus_get_standard_session_servicedirs (&dirs)) _dbus_assert_not_reached ("couldn't get standard dirs"); while ((link = _dbus_list_pop_first_link (&dirs))) { printf ("default service dir: %s\n", (char *)link->data); dbus_free (link->data); _dbus_list_free_link (link); } dbus_free (dirs); return TRUE; } static dbus_bool_t print_replace_install_prefix(const char *s) { const char *s2 = _dbus_replace_install_prefix(s); if (!s2) return FALSE; fprintf(stdout, "replaced '%s' by '%s'\n", s, s2); return TRUE; } int main (int argc, char **argv) { if (!print_install_root()) return -1; if (!print_service_dirs()) return -2; if (!print_replace_install_prefix(DBUS_BINDIR "/dbus-daemon")) return -3; if (!print_replace_install_prefix("c:\\Windows\\System32\\testfile")) return -4; return 0; } dbus-1.10.6/test/manual-dir-iter.c0000644000175000017500000000360512602773110016656 0ustar00smcvsmcv00000000000000#include #include "test-utils.h" #include "dbus/dbus-macros.h" #include "dbus/dbus-sysdeps.h" static void oom (const char *doing) _DBUS_GNUC_NORETURN; static void die (const char *message) _DBUS_GNUC_NORETURN; void oom (const char *doing) { fprintf (stderr, "*** manual-dir-iter: OOM while %s\n", doing); exit (1); } void die (const char *message) { fprintf (stderr, "*** manual-dir-iter: %s\n", message); exit (1); } static void debug (const char *message) { fprintf (stdout, "+++ manual-dir-iter: %s\n", message); } int main (int argc, char **argv) { DBusString filename; DBusString dirname; DBusError tmp_error; DBusDirIter *dir; if (argc != 2) die ("syntax: manual-dir-iter "); dbus_error_init (&tmp_error); if (!_dbus_string_init (&filename)) oom ("init filename"); if (!_dbus_string_init (&dirname)) oom ("init dirname"); _dbus_string_append (&dirname, argv[1]); dir = _dbus_directory_open (&dirname, &tmp_error); if (dir == NULL) { fprintf (stderr, "could not open directory: %s: %s\n", tmp_error.name, tmp_error.message); exit(1); } while (_dbus_directory_get_next_file (dir, &filename, &tmp_error)) { DBusString full_path; if (!_dbus_string_init (&full_path)) { oom ("init full_path"); } if (!_dbus_string_copy (&dirname, 0, &full_path, 0)) { oom ("copying full_path to dirname"); } if (!_dbus_concat_dir_and_file (&full_path, &filename)) { oom ("concat full_path"); } debug (_dbus_string_get_const_data (&filename)); _dbus_string_free (&full_path); } if (dbus_error_is_set (&tmp_error)) die (tmp_error.message); _dbus_string_free (&filename); if (dir) _dbus_directory_close (dir); _dbus_verbose ("*** Test dir name exiting\n"); return 0; } dbus-1.10.6/test/manual-authz.c0000644000175000017500000002764112602773110016300 0ustar00smcvsmcv00000000000000/* Simple sanity-check for authentication and authorization. * * Copyright © 2010-2011 Nokia Corporation * Copyright © 2012 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #ifdef G_OS_UNIX #include #include #endif #include "test-utils.h" typedef struct { DBusError e; TestMainContext *ctx; DBusServer *normal_server; DBusServer *anon_allowed_server; DBusServer *anon_only_server; DBusServer *anon_mech_only_server; DBusServer *anon_disallowed_server; DBusServer *permissive_server; DBusServer *unhappy_server; DBusServer *same_uid_server; DBusServer *same_uid_or_anon_server; } Fixture; static void oom (void) G_GNUC_NORETURN; static void oom (void) { g_error ("out of memory"); abort (); } static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } static DBusHandlerResult server_message_cb (DBusConnection *conn, DBusMessage *message, void *data) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { dbus_connection_unref (conn); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) { DBusMessage *reply = dbus_message_new_method_return (message); const char *hello = "Hello, world!"; unsigned long uid; char *sid; if (dbus_connection_get_unix_user (conn, &uid)) { g_message ("message from uid %lu", uid); } else if (dbus_connection_get_windows_user (conn, &sid)) { if (sid == NULL) oom (); g_message ("message from sid \"%s\"", sid); dbus_free (sid); } else if (dbus_connection_get_is_anonymous (conn)) { g_message ("message from Anonymous"); } else { g_message ("message from ... someone?"); } if (reply == NULL) oom (); if (!dbus_message_append_args (reply, DBUS_TYPE_STRING, &hello, DBUS_TYPE_INVALID)) oom (); if (!dbus_connection_send (conn, reply, NULL)) oom (); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static dbus_bool_t permissive_unix_func (DBusConnection *conn, unsigned long uid, void *data) { g_message ("accepting Unix user %lu", uid); return TRUE; } static dbus_bool_t permissive_win_func (DBusConnection *conn, const char *sid, void *data) { g_message ("accepting Windows user \"%s\"", sid); return TRUE; } static dbus_bool_t broken_unix_func (DBusConnection *conn, unsigned long uid, void *data) { g_error ("libdbus called the Unix user function for an ANONYMOUS-only " "connection"); return FALSE; } static dbus_bool_t broken_win_func (DBusConnection *conn, const char *sid, void *data) { g_error ("libdbus called the Windows user function for an ANONYMOUS-only " "connection"); return FALSE; } static dbus_bool_t unhappy_unix_func (DBusConnection *conn, unsigned long uid, void *data) { g_message ("rejecting Unix user %lu", uid); return FALSE; } static dbus_bool_t unhappy_win_func (DBusConnection *conn, const char *sid, void *data) { g_message ("rejecting Windows user \"%s\"", sid); return FALSE; } static dbus_bool_t same_uid_unix_func (DBusConnection *conn, unsigned long uid, void *data) { g_message ("checking whether Unix user %lu owns this process", uid); /* I'd use _dbus_unix_user_is_process_owner(), but it's private... */ #ifdef G_OS_UNIX return (geteuid () == uid); #else return FALSE; #endif } static dbus_bool_t same_uid_win_func (DBusConnection *conn, const char *sid, void *data) { g_message ("checking whether Windows user \"%s\" owns this process", sid); g_message ("Stub implementation consistent with dbus-sysdeps-util-win: " "assume they do"); return TRUE; } static void new_conn_cb (DBusServer *server, DBusConnection *conn, void *data) { Fixture *f = data; dbus_connection_ref (conn); test_connection_setup (f->ctx, conn); if (!dbus_connection_add_filter (conn, server_message_cb, f, NULL)) oom (); if (server == f->normal_server) { } else if (server == f->anon_allowed_server) { dbus_connection_set_allow_anonymous (conn, TRUE); } else if (server == f->anon_only_server) { dbus_connection_set_allow_anonymous (conn, TRUE); dbus_connection_set_unix_user_function (conn, unhappy_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, unhappy_win_func, f, NULL); } else if (server == f->anon_mech_only_server) { dbus_connection_set_allow_anonymous (conn, TRUE); /* should never get called */ dbus_connection_set_unix_user_function (conn, broken_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, broken_win_func, f, NULL); } else if (server == f->anon_disallowed_server) { dbus_connection_set_allow_anonymous (conn, FALSE); /* should never get called */ dbus_connection_set_unix_user_function (conn, broken_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, broken_win_func, f, NULL); } else if (server == f->permissive_server) { dbus_connection_set_unix_user_function (conn, permissive_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, permissive_win_func, f, NULL); } else if (server == f->unhappy_server) { dbus_connection_set_unix_user_function (conn, unhappy_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, unhappy_win_func, f, NULL); } else if (server == f->same_uid_server) { dbus_connection_set_unix_user_function (conn, same_uid_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, same_uid_win_func, f, NULL); } else if (server == f->same_uid_or_anon_server) { dbus_connection_set_allow_anonymous (conn, TRUE); dbus_connection_set_unix_user_function (conn, same_uid_unix_func, f, NULL); dbus_connection_set_windows_user_function (conn, same_uid_win_func, f, NULL); } else { g_assert_not_reached (); } } static void setup (Fixture *f, const gchar *listen_addr) { const char *only_anon[] = { "ANONYMOUS", NULL }; char *connect_addr; f->normal_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->normal_server != NULL); dbus_server_set_new_connection_function (f->normal_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->normal_server); connect_addr = dbus_server_get_address (f->normal_server); g_message ("Normal server:\n%s", connect_addr); dbus_free (connect_addr); f->anon_allowed_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->anon_allowed_server != NULL); dbus_server_set_new_connection_function (f->anon_allowed_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->anon_allowed_server); connect_addr = dbus_server_get_address (f->anon_allowed_server); g_message ("Anonymous-allowed server:\n%s", connect_addr); dbus_free (connect_addr); f->anon_only_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->anon_only_server != NULL); dbus_server_set_new_connection_function (f->anon_only_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->anon_only_server); connect_addr = dbus_server_get_address (f->anon_only_server); g_message ("Anonymous-only server:\n%s", connect_addr); dbus_free (connect_addr); f->anon_mech_only_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->anon_mech_only_server != NULL); dbus_server_set_auth_mechanisms (f->anon_mech_only_server, only_anon); dbus_server_set_new_connection_function (f->anon_mech_only_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->anon_mech_only_server); connect_addr = dbus_server_get_address (f->anon_mech_only_server); g_message ("Anon mech only server:\n%s", connect_addr); dbus_free (connect_addr); f->anon_disallowed_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->anon_disallowed_server != NULL); dbus_server_set_auth_mechanisms (f->anon_disallowed_server, only_anon); dbus_server_set_new_connection_function (f->anon_disallowed_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->anon_disallowed_server); connect_addr = dbus_server_get_address (f->anon_disallowed_server); g_message ("Anonymous-disallowed server:\n%s", connect_addr); dbus_free (connect_addr); f->permissive_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->permissive_server != NULL); dbus_server_set_new_connection_function (f->permissive_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->permissive_server); connect_addr = dbus_server_get_address (f->permissive_server); g_message ("Permissive server:\n%s", connect_addr); dbus_free (connect_addr); f->unhappy_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->unhappy_server != NULL); dbus_server_set_new_connection_function (f->unhappy_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->unhappy_server); connect_addr = dbus_server_get_address (f->unhappy_server); g_message ("Unhappy server:\n%s", connect_addr); dbus_free (connect_addr); f->same_uid_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->same_uid_server != NULL); dbus_server_set_new_connection_function (f->same_uid_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->same_uid_server); connect_addr = dbus_server_get_address (f->same_uid_server); g_message ("Same-UID server:\n%s", connect_addr); dbus_free (connect_addr); f->same_uid_or_anon_server = dbus_server_listen (listen_addr, &f->e); assert_no_error (&f->e); g_assert (f->same_uid_or_anon_server != NULL); dbus_server_set_new_connection_function (f->same_uid_or_anon_server, new_conn_cb, f, NULL); test_server_setup (f->ctx, f->same_uid_or_anon_server); connect_addr = dbus_server_get_address (f->same_uid_or_anon_server); g_message ("Same-UID-or-anon server:\n%s", connect_addr); dbus_free (connect_addr); } int main (int argc, char **argv) { Fixture f = { DBUS_ERROR_INIT, test_main_context_get () }; if (argc >= 2) setup (&f, argv[1]); else setup (&f, "tcp:host=127.0.0.1"); for (;;) test_main_context_iterate (f.ctx, TRUE); /* never returns */ } dbus-1.10.6/test/test-utils-glib.h0000644000175000017500000000631412602773110016721 0ustar00smcvsmcv00000000000000/* Utility functions for tests that rely on GLib * * Copyright © 2010-2011 Nokia Corporation * Copyright © 2013-2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef TEST_UTILS_GLIB_H #define TEST_UTILS_GLIB_H #include #include #include "test-utils.h" /* * Multi-user support for regression tests run with root privileges in * a continuous integration system. * * A developer would normally run the tests as their own uid. Tests run * as TEST_USER_ME are run, and the others are skipped. * * In a CI system that has access to root privileges, most tests should still * be run as an arbitrary non-root user, as above. * * Certain tests can usefully be run again, as root. When this is done, * tests using TEST_USER_ROOT, TEST_USER_MESSAGEBUS and/or TEST_USER_OTHER * can exercise situations that only arise when there's more than one uid. */ typedef enum { /* Whatever user happens to be running the regression test; * such tests also work on Windows */ TEST_USER_ME, /* Must be uid 0 on Unix; the test is skipped on Windows */ TEST_USER_ROOT, /* The user who would normally run the system bus. This is the DBUS_USER * from configure.ac, usually 'messagebus' but perhaps 'dbus' or * '_dbus'. */ TEST_USER_MESSAGEBUS, /* An unprivileged user who is neither root nor DBUS_USER. * This is DBUS_TEST_USER from configure.ac, usually 'nobody'. */ TEST_USER_OTHER } TestUser; #define test_assert_no_error(e) _test_assert_no_error (e, __FILE__, __LINE__) void _test_assert_no_error (const DBusError *e, const char *file, int line); gchar *test_get_dbus_daemon (const gchar *config_file, TestUser user, GPid *daemon_pid); DBusConnection *test_connect_to_bus (TestMainContext *ctx, const gchar *address); DBusConnection *test_connect_to_bus_as_user (TestMainContext *ctx, const char *address, TestUser user); void test_kill_pid (GPid pid); void test_init (int *argcp, char ***argvp); void test_progress (char symbol); #if !GLIB_CHECK_VERSION (2, 38, 0) #define g_test_skip(s) my_test_skip (s) static inline void my_test_skip (const gchar *s) { g_test_message ("SKIP: %s", s); } #endif #endif dbus-1.10.6/test/test-utils-glib.c0000644000175000017500000002665112613421022016714 0ustar00smcvsmcv00000000000000/* Utility functions for tests that rely on GLib * * Copyright © 2010-2011 Nokia Corporation * Copyright © 2013-2015 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "test-utils-glib.h" #include #ifdef DBUS_WIN # include # include #else # include # include # include # include # include #endif #include #include #include #ifdef G_OS_WIN # define isatty(x) _isatty(x) #endif void _test_assert_no_error (const DBusError *e, const char *file, int line) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("%s:%d: expected success but got error: %s: %s", file, line, e->name, e->message); } #ifdef DBUS_UNIX static void child_setup (gpointer user_data) { const struct passwd *pwd = user_data; uid_t uid = geteuid (); if (pwd == NULL || (pwd->pw_uid == uid && getuid () == uid)) return; if (uid != 0) g_error ("not currently euid 0: %lu", (unsigned long) uid); if (setuid (pwd->pw_uid) != 0) g_error ("could not setuid (%lu): %s", (unsigned long) pwd->pw_uid, g_strerror (errno)); uid = getuid (); if (uid != pwd->pw_uid) g_error ("after successful setuid (%lu) my uid is %ld", (unsigned long) pwd->pw_uid, (unsigned long) uid); uid = geteuid (); if (uid != pwd->pw_uid) g_error ("after successful setuid (%lu) my euid is %ld", (unsigned long) pwd->pw_uid, (unsigned long) uid); } #endif static gchar * spawn_dbus_daemon (const gchar *binary, const gchar *configuration, const gchar *listen_address, TestUser user, GPid *daemon_pid) { GError *error = NULL; GString *address; gint address_fd; GPtrArray *argv; #ifdef DBUS_UNIX const struct passwd *pwd = NULL; #endif if (user != TEST_USER_ME) { #ifdef DBUS_UNIX if (getuid () != 0) { g_test_skip ("cannot use alternative uid when not uid 0"); return NULL; } switch (user) { case TEST_USER_ROOT: break; case TEST_USER_MESSAGEBUS: pwd = getpwnam (DBUS_USER); if (pwd == NULL) { gchar *message = g_strdup_printf ("user '%s' does not exist", DBUS_USER); g_test_skip (message); g_free (message); return NULL; } break; case TEST_USER_OTHER: pwd = getpwnam (DBUS_TEST_USER); if (pwd == NULL) { gchar *message = g_strdup_printf ("user '%s' does not exist", DBUS_TEST_USER); g_test_skip (message); g_free (message); return NULL; } break; default: g_assert_not_reached (); } #else g_test_skip ("cannot use alternative uid on Windows"); return NULL; #endif } argv = g_ptr_array_new_with_free_func (g_free); g_ptr_array_add (argv, g_strdup (binary)); g_ptr_array_add (argv, g_strdup (configuration)); g_ptr_array_add (argv, g_strdup ("--nofork")); g_ptr_array_add (argv, g_strdup ("--print-address=1")); /* stdout */ if (listen_address != NULL) g_ptr_array_add (argv, g_strdup (listen_address)); #ifdef DBUS_UNIX g_ptr_array_add (argv, g_strdup ("--systemd-activation")); #endif g_ptr_array_add (argv, NULL); g_spawn_async_with_pipes (NULL, /* working directory */ (gchar **) argv->pdata, NULL, /* envp */ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, #ifdef DBUS_UNIX child_setup, (gpointer) pwd, #else NULL, NULL, #endif daemon_pid, NULL, /* child's stdin = /dev/null */ &address_fd, NULL, /* child's stderr = our stderr */ &error); g_assert_no_error (error); g_ptr_array_free (argv, TRUE); address = g_string_new (NULL); /* polling until the dbus-daemon writes out its address is a bit stupid, * but at least it's simple, unlike dbus-launch... in principle we could * use select() here, but life's too short */ while (1) { gssize bytes; gchar buf[4096]; gchar *newline; bytes = read (address_fd, buf, sizeof (buf)); if (bytes > 0) g_string_append_len (address, buf, bytes); newline = strchr (address->str, '\n'); if (newline != NULL) { if ((newline > address->str) && ('\r' == newline[-1])) newline -= 1; g_string_truncate (address, newline - address->str); break; } g_usleep (G_USEC_PER_SEC / 10); } g_close (address_fd, NULL); return g_string_free (address, FALSE); } gchar * test_get_dbus_daemon (const gchar *config_file, TestUser user, GPid *daemon_pid) { gchar *dbus_daemon; gchar *arg; const gchar *listen_address = NULL; gchar *address; /* we often have to override this because on Windows, the default may be * autolaunch:, which is globally-scoped and hence unsuitable for * regression tests */ listen_address = "--address=" TEST_LISTEN; if (config_file != NULL) { if (g_getenv ("DBUS_TEST_DATA") == NULL) { g_test_message ("set DBUS_TEST_DATA to a directory containing %s", config_file); g_test_skip ("DBUS_TEST_DATA not set"); return NULL; } arg = g_strdup_printf ( "--config-file=%s/%s", g_getenv ("DBUS_TEST_DATA"), config_file); /* The configuration file is expected to give a suitable address, * do not override it */ listen_address = NULL; } else if (g_getenv ("DBUS_TEST_DATADIR") != NULL) { arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf", g_getenv ("DBUS_TEST_DATADIR")); } else if (g_getenv ("DBUS_TEST_DATA") != NULL) { arg = g_strdup_printf ( "--config-file=%s/valid-config-files/session.conf", g_getenv ("DBUS_TEST_DATA")); } else { arg = g_strdup ("--session"); } dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON")); if (dbus_daemon == NULL) dbus_daemon = g_strdup ("dbus-daemon"); if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL) { if (config_file != NULL || user != TEST_USER_ME) { g_test_skip ("cannot use DBUS_TEST_DAEMON_ADDRESS for " "unusally-configured dbus-daemon"); address = NULL; } else { address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS")); } } else { address = spawn_dbus_daemon (dbus_daemon, arg, listen_address, user, daemon_pid); } g_free (dbus_daemon); g_free (arg); return address; } DBusConnection * test_connect_to_bus (TestMainContext *ctx, const gchar *address) { DBusConnection *conn; DBusError error = DBUS_ERROR_INIT; dbus_bool_t ok; conn = dbus_connection_open_private (address, &error); test_assert_no_error (&error); g_assert (conn != NULL); ok = dbus_bus_register (conn, &error); test_assert_no_error (&error); g_assert (ok); g_assert (dbus_bus_get_unique_name (conn) != NULL); test_connection_setup (ctx, conn); return conn; } DBusConnection * test_connect_to_bus_as_user (TestMainContext *ctx, const char *address, TestUser user) { /* For now we only do tests like this on Linux, because I don't know how * safe this use of setresuid() is on other platforms */ #if defined(HAVE_GETRESUID) && defined(HAVE_SETRESUID) && defined(__linux__) uid_t ruid, euid, suid; const struct passwd *pwd; DBusConnection *conn; const char *username; switch (user) { case TEST_USER_ME: return test_connect_to_bus (ctx, address); case TEST_USER_ROOT: username = "root"; break; case TEST_USER_MESSAGEBUS: username = DBUS_USER; break; case TEST_USER_OTHER: username = DBUS_TEST_USER; break; default: g_return_val_if_reached (NULL); } if (getresuid (&ruid, &euid, &suid) != 0) g_error ("getresuid: %s", g_strerror (errno)); if (ruid != 0 || euid != 0 || suid != 0) { g_test_message ("not uid 0 (ruid=%ld euid=%ld suid=%ld)", (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid); g_test_skip ("not uid 0"); return NULL; } pwd = getpwnam (username); if (pwd == NULL) { g_test_message ("getpwnam(\"%s\"): %s", username, g_strerror (errno)); g_test_skip ("not uid 0"); return NULL; } /* Impersonate the desired user while we connect to the bus. * This should work, because we're root. */ if (setresuid (pwd->pw_uid, pwd->pw_uid, 0) != 0) g_error ("setresuid(%ld, (same), 0): %s", (unsigned long) pwd->pw_uid, g_strerror (errno)); conn = test_connect_to_bus (ctx, address); /* go back to our saved uid */ if (setresuid (0, 0, 0) != 0) g_error ("setresuid(0, 0, 0): %s", g_strerror (errno)); return conn; #else switch (user) { case TEST_USER_ME: return test_connect_to_bus (ctx, address); default: g_test_skip ("setresuid() not available, or unsure about " "credentials-passing semantics on this platform"); return NULL; } #endif } void test_kill_pid (GPid pid) { #ifdef DBUS_WIN if (pid != NULL) TerminateProcess (pid, 1); #else if (pid > 0) kill (pid, SIGTERM); #endif } static gboolean time_out (gpointer data) { g_error ("timed out"); return FALSE; } #ifdef G_OS_UNIX static void wrap_abort (int signal) { abort (); } #endif void test_init (int *argcp, char ***argvp) { g_test_init (argcp, argvp, NULL); g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); /* Prevent tests from hanging forever. This is intended to be long enough * that any reasonable regression test on any reasonable hardware would * have finished. */ #define TIMEOUT 60 g_timeout_add_seconds (TIMEOUT, time_out, NULL); #ifdef G_OS_UNIX /* The GLib main loop might not be running (we don't use it in every * test). Die with SIGALRM shortly after if necessary. */ alarm (TIMEOUT + 10); /* Get a core dump from the SIGALRM. */ { struct sigaction act = { }; act.sa_handler = wrap_abort; sigaction (SIGALRM, &act, NULL); } #endif } void test_progress (char symbol) { if (g_test_verbose () && isatty (1)) g_print ("%c", symbol); } dbus-1.10.6/test/test-utils.h0000644000175000017500000000244212602773110016004 0ustar00smcvsmcv00000000000000#ifndef TEST_UTILS_H #define TEST_UTILS_H #include #include #include #include #include typedef DBusLoop TestMainContext; TestMainContext *test_main_context_get (void); TestMainContext *test_main_context_ref (TestMainContext *ctx); void test_main_context_unref (TestMainContext *ctx); void test_main_context_iterate (TestMainContext *ctx, dbus_bool_t may_block); dbus_bool_t test_connection_setup (TestMainContext *ctx, DBusConnection *connection); void test_connection_shutdown (TestMainContext *ctx, DBusConnection *connection); dbus_bool_t test_server_setup (TestMainContext *ctx, DBusServer *server); void test_server_shutdown (TestMainContext *ctx, DBusServer *server); void test_pending_call_store_reply (DBusPendingCall *pc, void *data); #endif dbus-1.10.6/test/test-utils.c0000644000175000017500000001752012602773110016002 0ustar00smcvsmcv00000000000000#include #include "test-utils.h" typedef struct { DBusLoop *loop; DBusConnection *connection; } CData; static dbus_bool_t add_watch (DBusWatch *watch, void *data) { CData *cd = data; return _dbus_loop_add_watch (cd->loop, watch); } static void remove_watch (DBusWatch *watch, void *data) { CData *cd = data; _dbus_loop_remove_watch (cd->loop, watch); } static void toggle_watch (DBusWatch *watch, void *data) { CData *cd = data; _dbus_loop_toggle_watch (cd->loop, watch); } static dbus_bool_t add_timeout (DBusTimeout *timeout, void *data) { CData *cd = data; return _dbus_loop_add_timeout (cd->loop, timeout); } static void remove_timeout (DBusTimeout *timeout, void *data) { CData *cd = data; _dbus_loop_remove_timeout (cd->loop, timeout); } static void dispatch_status_function (DBusConnection *connection, DBusDispatchStatus new_status, void *data) { DBusLoop *loop = data; if (new_status != DBUS_DISPATCH_COMPLETE) { while (!_dbus_loop_queue_dispatch (loop, connection)) _dbus_wait_for_memory (); } } static void cdata_free (void *data) { CData *cd = data; dbus_connection_unref (cd->connection); _dbus_loop_unref (cd->loop); dbus_free (cd); } static CData* cdata_new (DBusLoop *loop, DBusConnection *connection) { CData *cd; cd = dbus_new0 (CData, 1); if (cd == NULL) return NULL; cd->loop = loop; cd->connection = connection; dbus_connection_ref (cd->connection); _dbus_loop_ref (cd->loop); return cd; } dbus_bool_t test_connection_setup (TestMainContext *ctx, DBusConnection *connection) { DBusLoop *loop = ctx; CData *cd; cd = NULL; dbus_connection_set_dispatch_status_function (connection, dispatch_status_function, loop, NULL); cd = cdata_new (loop, connection); if (cd == NULL) goto nomem; if (!dbus_connection_set_watch_functions (connection, add_watch, remove_watch, toggle_watch, cd, cdata_free)) goto nomem; cd = cdata_new (loop, connection); if (cd == NULL) goto nomem; if (!dbus_connection_set_timeout_functions (connection, add_timeout, remove_timeout, NULL, cd, cdata_free)) goto nomem; if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) { if (!_dbus_loop_queue_dispatch (loop, connection)) goto nomem; } return TRUE; nomem: if (cd) cdata_free (cd); dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL); return FALSE; } static void die (const char *message) { fprintf (stderr, "*** %s", message); exit (1); } void test_connection_shutdown (TestMainContext *ctx, DBusConnection *connection) { if (!dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL)) die ("setting watch functions to NULL failed"); if (!dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL)) die ("setting timeout functions to NULL failed"); dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); } typedef struct { DBusLoop *loop; DBusServer *server; } ServerData; static void serverdata_free (void *data) { ServerData *sd = data; dbus_server_unref (sd->server); _dbus_loop_unref (sd->loop); dbus_free (sd); } static ServerData* serverdata_new (DBusLoop *loop, DBusServer *server) { ServerData *sd; sd = dbus_new0 (ServerData, 1); if (sd == NULL) return NULL; sd->loop = loop; sd->server = server; dbus_server_ref (sd->server); _dbus_loop_ref (sd->loop); return sd; } static dbus_bool_t add_server_watch (DBusWatch *watch, void *data) { ServerData *context = data; return _dbus_loop_add_watch (context->loop, watch); } static void toggle_server_watch (DBusWatch *watch, void *data) { ServerData *context = data; _dbus_loop_toggle_watch (context->loop, watch); } static void remove_server_watch (DBusWatch *watch, void *data) { ServerData *context = data; _dbus_loop_remove_watch (context->loop, watch); } static dbus_bool_t add_server_timeout (DBusTimeout *timeout, void *data) { ServerData *context = data; return _dbus_loop_add_timeout (context->loop, timeout); } static void remove_server_timeout (DBusTimeout *timeout, void *data) { ServerData *context = data; _dbus_loop_remove_timeout (context->loop, timeout); } dbus_bool_t test_server_setup (TestMainContext *ctx, DBusServer *server) { DBusLoop *loop = ctx; ServerData *sd; sd = serverdata_new (loop, server); if (sd == NULL) goto nomem; if (!dbus_server_set_watch_functions (server, add_server_watch, remove_server_watch, toggle_server_watch, sd, serverdata_free)) { goto nomem; } sd = serverdata_new (loop, server); if (sd == NULL) goto nomem; if (!dbus_server_set_timeout_functions (server, add_server_timeout, remove_server_timeout, NULL, sd, serverdata_free)) { goto nomem; } return TRUE; nomem: if (sd) serverdata_free (sd); test_server_shutdown (loop, server); return FALSE; } void test_server_shutdown (TestMainContext *ctx, DBusServer *server) { dbus_server_disconnect (server); if (!dbus_server_set_watch_functions (server, NULL, NULL, NULL, NULL, NULL)) die ("setting watch functions to NULL failed"); if (!dbus_server_set_timeout_functions (server, NULL, NULL, NULL, NULL, NULL)) die ("setting timeout functions to NULL failed"); } TestMainContext * test_main_context_get (void) { return _dbus_loop_new (); } TestMainContext * test_main_context_ref (TestMainContext *ctx) { return _dbus_loop_ref (ctx); } void test_main_context_unref (TestMainContext *ctx) { _dbus_loop_unref (ctx); } void test_main_context_iterate (TestMainContext *ctx, dbus_bool_t may_block) { _dbus_loop_iterate (ctx, may_block); } void test_pending_call_store_reply (DBusPendingCall *pc, void *data) { DBusMessage **message_p = data; *message_p = dbus_pending_call_steal_reply (pc); _dbus_assert (*message_p != NULL); } dbus-1.10.6/test/Makefile.in0000644000175000017500000023665012627362261015605 0ustar00smcvsmcv00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @DBUS_WITH_GLIB_TRUE@am__append_1 = \ @DBUS_WITH_GLIB_TRUE@ test-utils-glib.c \ @DBUS_WITH_GLIB_TRUE@ test-utils-glib.h \ @DBUS_WITH_GLIB_TRUE@ $(NULL) TESTS = $(am__append_3) $(am__EXEEXT_10) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@am__append_2 = test-bus-launch-helper.sh \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ test-bus-system.sh @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@am__append_3 = $(wrap_bus_tests) $(wrap_dbus_tests) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@am__append_4 = $(wrap_bus_tests) $(wrap_dbus_tests) noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_8) testexec_PROGRAMS = $(am__EXEEXT_9) @DBUS_WIN_TRUE@am__append_5 = manual-paths @DBUS_WITH_GLIB_TRUE@am__append_6 = \ @DBUS_WITH_GLIB_TRUE@ test-corrupt \ @DBUS_WITH_GLIB_TRUE@ test-dbus-daemon \ @DBUS_WITH_GLIB_TRUE@ test-dbus-daemon-eavesdrop \ @DBUS_WITH_GLIB_TRUE@ test-fdpass \ @DBUS_WITH_GLIB_TRUE@ test-monitor \ @DBUS_WITH_GLIB_TRUE@ test-loopback \ @DBUS_WITH_GLIB_TRUE@ test-marshal \ @DBUS_WITH_GLIB_TRUE@ test-refs \ @DBUS_WITH_GLIB_TRUE@ test-relay \ @DBUS_WITH_GLIB_TRUE@ test-syntax \ @DBUS_WITH_GLIB_TRUE@ test-syslog \ @DBUS_WITH_GLIB_TRUE@ test-uid-permissions \ @DBUS_WITH_GLIB_TRUE@ $(NULL) @DBUS_UNIX_TRUE@@DBUS_WITH_GLIB_TRUE@am__append_7 = \ @DBUS_UNIX_TRUE@@DBUS_WITH_GLIB_TRUE@ test-sd-activation \ @DBUS_UNIX_TRUE@@DBUS_WITH_GLIB_TRUE@ $(NULL) @DBUS_WITH_GLIB_TRUE@am__append_8 = \ @DBUS_WITH_GLIB_TRUE@ manual-authz \ @DBUS_WITH_GLIB_TRUE@ $(NULL) @DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_9 = $(installable_tests) @DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_10 = $(installable_tests) @DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_11 = $(installable_tests) $(installable_manual_tests) @DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_12 = $(installable_test_meta) \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(installable_test_meta_with_config) @DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_13 = $(installable_tests) $(installable_manual_tests) subdir = test ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ $(top_srcdir)/m4/compiler.m4 \ $(top_srcdir)/m4/ld-version-script.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/m4/tp-compiler-flag.m4 \ $(top_srcdir)/m4/tp-compiler-warnings.m4 \ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libdbus_testutils_la_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la \ $(top_builddir)/dbus/libdbus-internal.la am__libdbus_testutils_la_SOURCES_DIST = test-utils.c test-utils.h \ test-utils-glib.c test-utils-glib.h @DBUS_WITH_GLIB_TRUE@am__objects_1 = test-utils-glib.lo am_libdbus_testutils_la_OBJECTS = test-utils.lo $(am__objects_1) libdbus_testutils_la_OBJECTS = $(am_libdbus_testutils_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@am__EXEEXT_1 = test-spawn$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-exit$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-names$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-segfault$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-service$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-shell-service$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-sleep-forever$(EXEEXT) @DBUS_WITH_GLIB_TRUE@am__EXEEXT_2 = test-corrupt$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-dbus-daemon$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-dbus-daemon-eavesdrop$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-fdpass$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-monitor$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-loopback$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-marshal$(EXEEXT) test-refs$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-relay$(EXEEXT) test-syntax$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-syslog$(EXEEXT) \ @DBUS_WITH_GLIB_TRUE@ test-uid-permissions$(EXEEXT) @DBUS_UNIX_TRUE@@DBUS_WITH_GLIB_TRUE@am__EXEEXT_3 = test-sd-activation$(EXEEXT) am__EXEEXT_4 = test-shell$(EXEEXT) test-printf$(EXEEXT) \ $(am__EXEEXT_2) $(am__EXEEXT_3) @DBUS_WIN_TRUE@am__EXEEXT_5 = manual-paths$(EXEEXT) @DBUS_WITH_GLIB_TRUE@am__EXEEXT_6 = manual-authz$(EXEEXT) am__EXEEXT_7 = manual-dir-iter$(EXEEXT) manual-tcp$(EXEEXT) \ $(am__EXEEXT_5) $(am__EXEEXT_6) @DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_8 = $(am__EXEEXT_4) \ @DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_7) @DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_9 = $(am__EXEEXT_4) \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_7) am__installdirs = "$(DESTDIR)$(testexecdir)" \ "$(DESTDIR)$(testmetadir)" PROGRAMS = $(noinst_PROGRAMS) $(testexec_PROGRAMS) am_manual_authz_OBJECTS = manual-authz.$(OBJEXT) manual_authz_OBJECTS = $(am_manual_authz_OBJECTS) am__DEPENDENCIES_1 = manual_authz_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_manual_dir_iter_OBJECTS = manual-dir-iter.$(OBJEXT) manual_dir_iter_OBJECTS = $(am_manual_dir_iter_OBJECTS) manual_dir_iter_DEPENDENCIES = \ $(top_builddir)/dbus/libdbus-internal.la am_manual_paths_OBJECTS = manual-paths.$(OBJEXT) manual_paths_OBJECTS = $(am_manual_paths_OBJECTS) manual_paths_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la am_manual_tcp_OBJECTS = manual-tcp.$(OBJEXT) manual_tcp_OBJECTS = $(am_manual_tcp_OBJECTS) manual_tcp_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la am_test_corrupt_OBJECTS = corrupt.$(OBJEXT) test_corrupt_OBJECTS = $(am_test_corrupt_OBJECTS) test_corrupt_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_dbus_daemon_OBJECTS = dbus-daemon.$(OBJEXT) test_dbus_daemon_OBJECTS = $(am_test_dbus_daemon_OBJECTS) test_dbus_daemon_DEPENDENCIES = libdbus-testutils.la \ $(am__DEPENDENCIES_1) am_test_dbus_daemon_eavesdrop_OBJECTS = \ dbus-daemon-eavesdrop.$(OBJEXT) test_dbus_daemon_eavesdrop_OBJECTS = \ $(am_test_dbus_daemon_eavesdrop_OBJECTS) test_dbus_daemon_eavesdrop_DEPENDENCIES = libdbus-testutils.la \ $(am__DEPENDENCIES_1) test_exit_SOURCES = test-exit.c test_exit_OBJECTS = test-exit.$(OBJEXT) test_exit_LDADD = $(LDADD) am_test_fdpass_OBJECTS = fdpass.$(OBJEXT) test_fdpass_OBJECTS = $(am_test_fdpass_OBJECTS) test_fdpass_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_loopback_OBJECTS = loopback.$(OBJEXT) test_loopback_OBJECTS = $(am_test_loopback_OBJECTS) test_loopback_DEPENDENCIES = libdbus-testutils.la \ $(am__DEPENDENCIES_1) am_test_marshal_OBJECTS = marshal.$(OBJEXT) test_marshal_OBJECTS = $(am_test_marshal_OBJECTS) test_marshal_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_monitor_OBJECTS = monitor.$(OBJEXT) test_monitor_OBJECTS = $(am_test_monitor_OBJECTS) test_monitor_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) test_names_SOURCES = test-names.c test_names_OBJECTS = test-names.$(OBJEXT) test_names_DEPENDENCIES = libdbus-testutils.la am__dirstamp = $(am__leading_dot)dirstamp am_test_printf_OBJECTS = internals/printf.$(OBJEXT) test_printf_OBJECTS = $(am_test_printf_OBJECTS) test_printf_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la am_test_refs_OBJECTS = internals/refs.$(OBJEXT) test_refs_OBJECTS = $(am_test_refs_OBJECTS) test_refs_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_relay_OBJECTS = relay.$(OBJEXT) test_relay_OBJECTS = $(am_test_relay_OBJECTS) test_relay_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am__test_sd_activation_SOURCES_DIST = sd-activation.c @DBUS_UNIX_TRUE@am_test_sd_activation_OBJECTS = \ @DBUS_UNIX_TRUE@ sd-activation.$(OBJEXT) test_sd_activation_OBJECTS = $(am_test_sd_activation_OBJECTS) @DBUS_UNIX_TRUE@test_sd_activation_DEPENDENCIES = \ @DBUS_UNIX_TRUE@ libdbus-testutils.la $(am__DEPENDENCIES_1) test_segfault_SOURCES = test-segfault.c test_segfault_OBJECTS = test-segfault.$(OBJEXT) test_segfault_LDADD = $(LDADD) test_service_SOURCES = test-service.c test_service_OBJECTS = test-service.$(OBJEXT) test_service_DEPENDENCIES = libdbus-testutils.la am_test_shell_OBJECTS = shell-test.$(OBJEXT) test_shell_OBJECTS = $(am_test_shell_OBJECTS) test_shell_DEPENDENCIES = libdbus-testutils.la test_shell_service_SOURCES = test-shell-service.c test_shell_service_OBJECTS = test-shell-service.$(OBJEXT) test_shell_service_DEPENDENCIES = libdbus-testutils.la test_sleep_forever_SOURCES = test-sleep-forever.c test_sleep_forever_OBJECTS = test-sleep-forever.$(OBJEXT) test_sleep_forever_LDADD = $(LDADD) am_test_spawn_OBJECTS = spawn-test.$(OBJEXT) test_spawn_OBJECTS = $(am_test_spawn_OBJECTS) test_spawn_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la am_test_syntax_OBJECTS = syntax.$(OBJEXT) test_syntax_OBJECTS = $(am_test_syntax_OBJECTS) test_syntax_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_syslog_OBJECTS = internals/syslog.$(OBJEXT) test_syslog_OBJECTS = $(am_test_syslog_OBJECTS) test_syslog_DEPENDENCIES = libdbus-testutils.la $(am__DEPENDENCIES_1) am_test_uid_permissions_OBJECTS = uid-permissions.$(OBJEXT) test_uid_permissions_OBJECTS = $(am_test_uid_permissions_OBJECTS) test_uid_permissions_DEPENDENCIES = libdbus-testutils.la \ $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libdbus_testutils_la_SOURCES) $(manual_authz_SOURCES) \ $(manual_dir_iter_SOURCES) $(manual_paths_SOURCES) \ $(manual_tcp_SOURCES) $(test_corrupt_SOURCES) \ $(test_dbus_daemon_SOURCES) \ $(test_dbus_daemon_eavesdrop_SOURCES) test-exit.c \ $(test_fdpass_SOURCES) $(test_loopback_SOURCES) \ $(test_marshal_SOURCES) $(test_monitor_SOURCES) test-names.c \ $(test_printf_SOURCES) $(test_refs_SOURCES) \ $(test_relay_SOURCES) $(test_sd_activation_SOURCES) \ test-segfault.c test-service.c $(test_shell_SOURCES) \ test-shell-service.c test-sleep-forever.c \ $(test_spawn_SOURCES) $(test_syntax_SOURCES) \ $(test_syslog_SOURCES) $(test_uid_permissions_SOURCES) DIST_SOURCES = $(am__libdbus_testutils_la_SOURCES_DIST) \ $(manual_authz_SOURCES) $(manual_dir_iter_SOURCES) \ $(manual_paths_SOURCES) $(manual_tcp_SOURCES) \ $(test_corrupt_SOURCES) $(test_dbus_daemon_SOURCES) \ $(test_dbus_daemon_eavesdrop_SOURCES) test-exit.c \ $(test_fdpass_SOURCES) $(test_loopback_SOURCES) \ $(test_marshal_SOURCES) $(test_monitor_SOURCES) test-names.c \ $(test_printf_SOURCES) $(test_refs_SOURCES) \ $(test_relay_SOURCES) $(am__test_sd_activation_SOURCES_DIST) \ test-segfault.c test-service.c $(test_shell_SOURCES) \ test-shell-service.c test-sleep-forever.c \ $(test_spawn_SOURCES) $(test_syntax_SOURCES) \ $(test_syslog_SOURCES) $(test_uid_permissions_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(noinst_DATA) $(testmeta_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ check recheck distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) @DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_10 = $(am__EXEEXT_4) TEST_SUITE_LOG = test-suite.log LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.sh.log=.log) SH_LOG_COMPILE = $(SH_LOG_COMPILER) $(AM_SH_LOG_FLAGS) $(SH_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ADT_LIBS = @ADT_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPARMOR_CFLAGS = @APPARMOR_CFLAGS@ APPARMOR_LIBS = @APPARMOR_LIBS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FILEVERSION = @BUILD_FILEVERSION@ BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIR_FROM_PKGSYSCONFDIR = @DATADIR_FROM_PKGSYSCONFDIR@ DBUS_BINDIR = @DBUS_BINDIR@ DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ DBUS_DATADIR = @DBUS_DATADIR@ DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ DBUS_PREFIX = @DBUS_PREFIX@ DBUS_SESSION_BUS_CONNECT_ADDRESS = @DBUS_SESSION_BUS_CONNECT_ADDRESS@ DBUS_SESSION_BUS_LISTEN_ADDRESS = @DBUS_SESSION_BUS_LISTEN_ADDRESS@ DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL = @DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL@ DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ DBUS_STATIC_BUILD_CPPFLAGS = @DBUS_STATIC_BUILD_CPPFLAGS@ DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ DBUS_TEST_DATA = @DBUS_TEST_DATA@ DBUS_TEST_EXEC = @DBUS_TEST_EXEC@ DBUS_TEST_USER = @DBUS_TEST_USER@ DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ DBUS_USER = @DBUS_USER@ DBUS_VERSION = @DBUS_VERSION@ DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ DBUS_X_LIBS = @DBUS_X_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUCKTYPE = @DUCKTYPE@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXPANDED_BINDIR = @EXPANDED_BINDIR@ EXPANDED_DATADIR = @EXPANDED_DATADIR@ EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ EXPANDED_PREFIX = @EXPANDED_PREFIX@ EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GREP = @GREP@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LAUNCHCTL = @LAUNCHCTL@ LAUNCHD_AGENT_DIR = @LAUNCHD_AGENT_DIR@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBDBUS_LIBS = @LIBDBUS_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ LT_REVISION = @LT_REVISION@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETWORK_libs = @NETWORK_libs@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RC = @RC@ R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ SED = @SED@ SELINUX_LIBS = @SELINUX_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOVERSION = @SOVERSION@ STRIP = @STRIP@ SYSCONFDIR_FROM_PKGDATADIR = @SYSCONFDIR_FROM_PKGDATADIR@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ SYSTEMD_LIBS = @SYSTEMD_LIBS@ TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ TEST_LISTEN = @TEST_LISTEN@ TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ THREAD_LIBS = @THREAD_LIBS@ VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ VALGRIND_LIBS = @VALGRIND_LIBS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XMKMF = @XMKMF@ XMLTO = @XMLTO@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ XSLTPROC = @XSLTPROC@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ YELP_BUILD = @YELP_BUILD@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ dbus_daemondir = @dbus_daemondir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemduserunitdir = @systemduserunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . name-test DIST_SUBDIRS = name-test CLEANFILES = $(am__append_4) $(noinst_DATA) XDG_RUNTIME_DIR \ installable $(NULL) EXTRA_DIST = glib-tap-test.sh tap-test.sh.in dbus-test-runner \ $(in_data) $(static_data) AM_CPPFLAGS = \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ -DDBUS_COMPILATION \ $(GLIB_CFLAGS) \ $(NULL) # improve backtraces from test stuff AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ noinst_LTLIBRARIES = libdbus-testutils.la libdbus_testutils_la_SOURCES = test-utils.c test-utils.h $(NULL) \ $(am__append_1) libdbus_testutils_la_LIBADD = \ $(top_builddir)/dbus/libdbus-1.la \ $(top_builddir)/dbus/libdbus-internal.la \ $(NULL) TEST_EXTENSIONS = .sh LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh LOG_COMPILER = $(srcdir)/glib-tap-test.sh SH_LOG_DRIVER = $(LOG_DRIVER) SH_LOG_COMPILER = $(SHELL) @DBUS_ENABLE_EMBEDDED_TESTS_FALSE@TEST_BINARIES = @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@TEST_BINARIES = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-spawn \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-exit \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-names \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-segfault \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-service \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-shell-service \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-sleep-forever \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ $(NULL) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@wrap_bus_tests = test-bus.sh \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ $(am__append_2) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@wrap_dbus_tests = test-dbus.sh test_service_LDADD = libdbus-testutils.la test_names_LDADD = libdbus-testutils.la test_shell_service_LDADD = libdbus-testutils.la test_shell_SOURCES = shell-test.c test_shell_LDADD = libdbus-testutils.la test_spawn_SOURCES = spawn-test.c test_spawn_LDADD = $(top_builddir)/dbus/libdbus-internal.la test_printf_SOURCES = internals/printf.c test_printf_LDADD = $(top_builddir)/dbus/libdbus-internal.la test_refs_SOURCES = internals/refs.c test_refs_LDADD = libdbus-testutils.la $(GLIB_LIBS) test_syslog_SOURCES = internals/syslog.c test_syslog_LDADD = libdbus-testutils.la $(GLIB_LIBS) manual_dir_iter_SOURCES = manual-dir-iter.c manual_dir_iter_LDADD = $(top_builddir)/dbus/libdbus-internal.la manual_paths_SOURCES = manual-paths.c manual_paths_LDADD = $(top_builddir)/dbus/libdbus-internal.la manual_tcp_SOURCES = manual-tcp.c manual_tcp_LDADD = $(top_builddir)/dbus/libdbus-internal.la testexecdir = $(libexecdir)/installed-tests/dbus testmetadir = $(datadir)/installed-tests/dbus testmeta_DATA = $(am__append_12) installable_tests = test-shell test-printf $(NULL) $(am__append_6) \ $(am__append_7) installable_manual_tests = manual-dir-iter manual-tcp $(NULL) \ $(am__append_5) $(am__append_8) installable_test_meta = $(installable_tests:=.test) installable_test_meta_with_config = $(installable_tests:=_with_config.test) installcheck_tests = $(am__append_10) installcheck_environment = \ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ export DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT); \ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \ export DBUS_TEST_DATADIR=$(DESTDIR)$(datadir); \ ${NULL} AM_TESTS_ENVIRONMENT = \ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ export DBUS_FATAL_WARNINGS=1; \ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \ $(NULL) manual_authz_SOURCES = manual-authz.c manual_authz_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_corrupt_SOURCES = corrupt.c test_corrupt_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_loopback_SOURCES = loopback.c test_loopback_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_relay_SOURCES = relay.c test_relay_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_dbus_daemon_SOURCES = dbus-daemon.c test_dbus_daemon_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_dbus_daemon_eavesdrop_SOURCES = dbus-daemon-eavesdrop.c test_dbus_daemon_eavesdrop_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) @DBUS_UNIX_TRUE@test_sd_activation_SOURCES = \ @DBUS_UNIX_TRUE@ sd-activation.c \ @DBUS_UNIX_TRUE@ $(NULL) @DBUS_UNIX_TRUE@test_sd_activation_LDADD = \ @DBUS_UNIX_TRUE@ libdbus-testutils.la \ @DBUS_UNIX_TRUE@ $(GLIB_LIBS) \ @DBUS_UNIX_TRUE@ $(NULL) test_marshal_SOURCES = marshal.c test_marshal_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_monitor_SOURCES = \ monitor.c \ $(NULL) test_monitor_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_syntax_SOURCES = syntax.c test_syntax_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_uid_permissions_SOURCES = \ uid-permissions.c \ $(NULL) test_uid_permissions_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_fdpass_SOURCES = \ fdpass.c \ $(NULL) test_fdpass_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) in_data = \ data/valid-config-files-system/debug-allow-all-fail.conf.in \ data/valid-config-files-system/debug-allow-all-pass.conf.in \ data/valid-config-files/debug-allow-all-sha1.conf.in \ data/valid-config-files/debug-allow-all.conf.in \ data/valid-config-files/finite-timeout.conf.in \ data/valid-config-files/forbidding.conf.in \ data/valid-config-files/incoming-limit.conf.in \ data/valid-config-files/multi-user.conf.in \ data/valid-config-files/systemd-activation.conf.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ $(NULL) static_data = \ name-test/tmp-session-like-system.conf \ data/auth/anonymous-client-successful.auth-script \ data/auth/anonymous-server-successful.auth-script \ data/auth/cancel.auth-script \ data/auth/client-out-of-mechanisms.auth-script \ data/auth/external-failed.auth-script \ data/auth/external-root.auth-script \ data/auth/external-silly.auth-script \ data/auth/external-successful.auth-script \ data/auth/extra-bytes.auth-script \ data/auth/fail-after-n-attempts.auth-script \ data/auth/fallback.auth-script \ data/auth/invalid-command-client.auth-script \ data/auth/invalid-command.auth-script \ data/auth/invalid-hex-encoding.auth-script \ data/auth/mechanisms.auth-script \ data/equiv-config-files/basic/basic-1.conf \ data/equiv-config-files/basic/basic-2.conf \ data/equiv-config-files/basic/basic.d/basic.conf \ data/equiv-config-files/entities/basic.d/basic.conf \ data/equiv-config-files/entities/entities-1.conf \ data/equiv-config-files/entities/entities-2.conf \ data/incomplete-messages/missing-body.message \ data/invalid-config-files/badselinux-1.conf \ data/invalid-config-files/badselinux-2.conf \ data/invalid-config-files/circular-1.conf \ data/invalid-config-files/circular-2.conf \ data/invalid-config-files/circular-3.conf \ data/invalid-config-files/not-well-formed.conf \ data/invalid-config-files/truncated-file.conf \ data/invalid-messages/array-of-nil.message \ data/invalid-messages/array-with-mixed-types.message \ data/invalid-messages/bad-boolean-array.message \ data/invalid-messages/bad-boolean.message \ data/invalid-messages/bad-endian.message \ data/invalid-messages/bad-header-field-alignment.message \ data/invalid-messages/boolean-has-no-value.message-raw \ data/invalid-messages/local-namespace.message \ data/invalid-messages/no-dot-in-name.message \ data/invalid-messages/not-nul-header-padding.message \ data/invalid-messages/overlong-name.message \ data/invalid-messages/too-little-header-padding.message \ data/invalid-messages/too-much-header-padding-by-far.message \ data/invalid-messages/too-much-header-padding.message \ data/invalid-messages/too-short-dict.message \ data/sha-1/Readme.txt \ data/sha-1/bit-hashes.sha1 \ data/sha-1/bit-messages.sha1 \ data/sha-1/byte-hashes.sha1 \ data/sha-1/byte-messages.sha1 \ data/systemd-activation/com.example.SystemdActivatable1.service \ data/systemd-activation/com.example.SystemdActivatable2.service \ data/systemd-activation/com.example.SystemdActivatable3.service \ data/systemd-activation/org.freedesktop.systemd1.service \ data/valid-config-files/basic.conf \ data/valid-config-files/basic.d/basic.conf \ data/valid-config-files/entities.conf \ data/valid-config-files/listen-unix-runtime.conf \ data/valid-config-files/many-rules.conf \ data/valid-config-files-system/system.d/test.conf \ data/valid-messages/array-of-array-of-uint32.message \ data/valid-messages/dict-simple.message \ data/valid-messages/dict.message \ data/valid-messages/emptiness.message \ data/valid-messages/lots-of-arguments.message \ data/valid-messages/no-padding.message \ data/valid-messages/opposite-endian.message \ data/valid-messages/recursive-types.message \ data/valid-messages/simplest-manual.message \ data/valid-messages/simplest.message \ data/valid-messages/standard-acquire-service.message \ data/valid-messages/standard-hello.message \ data/valid-messages/standard-list-services.message \ data/valid-messages/standard-service-exists.message \ data/valid-messages/unknown-header-field.message \ $(NULL) imported_data = \ data/valid-config-files/session.conf \ data/valid-config-files-system/system.conf \ $(NULL) noinst_DATA = $(imported_data) all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .log .o .obj .sh .sh$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libdbus-testutils.la: $(libdbus_testutils_la_OBJECTS) $(libdbus_testutils_la_DEPENDENCIES) $(EXTRA_libdbus_testutils_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libdbus_testutils_la_OBJECTS) $(libdbus_testutils_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-testexecPROGRAMS: $(testexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(testexec_PROGRAMS)'; test -n "$(testexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(testexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(testexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(testexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(testexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-testexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(testexec_PROGRAMS)'; test -n "$(testexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(testexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(testexecdir)" && rm -f $$files clean-testexecPROGRAMS: @list='$(testexec_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list manual-authz$(EXEEXT): $(manual_authz_OBJECTS) $(manual_authz_DEPENDENCIES) $(EXTRA_manual_authz_DEPENDENCIES) @rm -f manual-authz$(EXEEXT) $(AM_V_CCLD)$(LINK) $(manual_authz_OBJECTS) $(manual_authz_LDADD) $(LIBS) manual-dir-iter$(EXEEXT): $(manual_dir_iter_OBJECTS) $(manual_dir_iter_DEPENDENCIES) $(EXTRA_manual_dir_iter_DEPENDENCIES) @rm -f manual-dir-iter$(EXEEXT) $(AM_V_CCLD)$(LINK) $(manual_dir_iter_OBJECTS) $(manual_dir_iter_LDADD) $(LIBS) manual-paths$(EXEEXT): $(manual_paths_OBJECTS) $(manual_paths_DEPENDENCIES) $(EXTRA_manual_paths_DEPENDENCIES) @rm -f manual-paths$(EXEEXT) $(AM_V_CCLD)$(LINK) $(manual_paths_OBJECTS) $(manual_paths_LDADD) $(LIBS) manual-tcp$(EXEEXT): $(manual_tcp_OBJECTS) $(manual_tcp_DEPENDENCIES) $(EXTRA_manual_tcp_DEPENDENCIES) @rm -f manual-tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(manual_tcp_OBJECTS) $(manual_tcp_LDADD) $(LIBS) test-corrupt$(EXEEXT): $(test_corrupt_OBJECTS) $(test_corrupt_DEPENDENCIES) $(EXTRA_test_corrupt_DEPENDENCIES) @rm -f test-corrupt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_corrupt_OBJECTS) $(test_corrupt_LDADD) $(LIBS) test-dbus-daemon$(EXEEXT): $(test_dbus_daemon_OBJECTS) $(test_dbus_daemon_DEPENDENCIES) $(EXTRA_test_dbus_daemon_DEPENDENCIES) @rm -f test-dbus-daemon$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dbus_daemon_OBJECTS) $(test_dbus_daemon_LDADD) $(LIBS) test-dbus-daemon-eavesdrop$(EXEEXT): $(test_dbus_daemon_eavesdrop_OBJECTS) $(test_dbus_daemon_eavesdrop_DEPENDENCIES) $(EXTRA_test_dbus_daemon_eavesdrop_DEPENDENCIES) @rm -f test-dbus-daemon-eavesdrop$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dbus_daemon_eavesdrop_OBJECTS) $(test_dbus_daemon_eavesdrop_LDADD) $(LIBS) test-exit$(EXEEXT): $(test_exit_OBJECTS) $(test_exit_DEPENDENCIES) $(EXTRA_test_exit_DEPENDENCIES) @rm -f test-exit$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_exit_OBJECTS) $(test_exit_LDADD) $(LIBS) test-fdpass$(EXEEXT): $(test_fdpass_OBJECTS) $(test_fdpass_DEPENDENCIES) $(EXTRA_test_fdpass_DEPENDENCIES) @rm -f test-fdpass$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fdpass_OBJECTS) $(test_fdpass_LDADD) $(LIBS) test-loopback$(EXEEXT): $(test_loopback_OBJECTS) $(test_loopback_DEPENDENCIES) $(EXTRA_test_loopback_DEPENDENCIES) @rm -f test-loopback$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_loopback_OBJECTS) $(test_loopback_LDADD) $(LIBS) test-marshal$(EXEEXT): $(test_marshal_OBJECTS) $(test_marshal_DEPENDENCIES) $(EXTRA_test_marshal_DEPENDENCIES) @rm -f test-marshal$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_marshal_OBJECTS) $(test_marshal_LDADD) $(LIBS) test-monitor$(EXEEXT): $(test_monitor_OBJECTS) $(test_monitor_DEPENDENCIES) $(EXTRA_test_monitor_DEPENDENCIES) @rm -f test-monitor$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_monitor_OBJECTS) $(test_monitor_LDADD) $(LIBS) test-names$(EXEEXT): $(test_names_OBJECTS) $(test_names_DEPENDENCIES) $(EXTRA_test_names_DEPENDENCIES) @rm -f test-names$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_names_OBJECTS) $(test_names_LDADD) $(LIBS) internals/$(am__dirstamp): @$(MKDIR_P) internals @: > internals/$(am__dirstamp) internals/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) internals/$(DEPDIR) @: > internals/$(DEPDIR)/$(am__dirstamp) internals/printf.$(OBJEXT): internals/$(am__dirstamp) \ internals/$(DEPDIR)/$(am__dirstamp) test-printf$(EXEEXT): $(test_printf_OBJECTS) $(test_printf_DEPENDENCIES) $(EXTRA_test_printf_DEPENDENCIES) @rm -f test-printf$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_printf_OBJECTS) $(test_printf_LDADD) $(LIBS) internals/refs.$(OBJEXT): internals/$(am__dirstamp) \ internals/$(DEPDIR)/$(am__dirstamp) test-refs$(EXEEXT): $(test_refs_OBJECTS) $(test_refs_DEPENDENCIES) $(EXTRA_test_refs_DEPENDENCIES) @rm -f test-refs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_refs_OBJECTS) $(test_refs_LDADD) $(LIBS) test-relay$(EXEEXT): $(test_relay_OBJECTS) $(test_relay_DEPENDENCIES) $(EXTRA_test_relay_DEPENDENCIES) @rm -f test-relay$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_relay_OBJECTS) $(test_relay_LDADD) $(LIBS) test-sd-activation$(EXEEXT): $(test_sd_activation_OBJECTS) $(test_sd_activation_DEPENDENCIES) $(EXTRA_test_sd_activation_DEPENDENCIES) @rm -f test-sd-activation$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_sd_activation_OBJECTS) $(test_sd_activation_LDADD) $(LIBS) test-segfault$(EXEEXT): $(test_segfault_OBJECTS) $(test_segfault_DEPENDENCIES) $(EXTRA_test_segfault_DEPENDENCIES) @rm -f test-segfault$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_segfault_OBJECTS) $(test_segfault_LDADD) $(LIBS) test-service$(EXEEXT): $(test_service_OBJECTS) $(test_service_DEPENDENCIES) $(EXTRA_test_service_DEPENDENCIES) @rm -f test-service$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_service_OBJECTS) $(test_service_LDADD) $(LIBS) test-shell$(EXEEXT): $(test_shell_OBJECTS) $(test_shell_DEPENDENCIES) $(EXTRA_test_shell_DEPENDENCIES) @rm -f test-shell$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_shell_OBJECTS) $(test_shell_LDADD) $(LIBS) test-shell-service$(EXEEXT): $(test_shell_service_OBJECTS) $(test_shell_service_DEPENDENCIES) $(EXTRA_test_shell_service_DEPENDENCIES) @rm -f test-shell-service$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_shell_service_OBJECTS) $(test_shell_service_LDADD) $(LIBS) test-sleep-forever$(EXEEXT): $(test_sleep_forever_OBJECTS) $(test_sleep_forever_DEPENDENCIES) $(EXTRA_test_sleep_forever_DEPENDENCIES) @rm -f test-sleep-forever$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_sleep_forever_OBJECTS) $(test_sleep_forever_LDADD) $(LIBS) test-spawn$(EXEEXT): $(test_spawn_OBJECTS) $(test_spawn_DEPENDENCIES) $(EXTRA_test_spawn_DEPENDENCIES) @rm -f test-spawn$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_spawn_OBJECTS) $(test_spawn_LDADD) $(LIBS) test-syntax$(EXEEXT): $(test_syntax_OBJECTS) $(test_syntax_DEPENDENCIES) $(EXTRA_test_syntax_DEPENDENCIES) @rm -f test-syntax$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_syntax_OBJECTS) $(test_syntax_LDADD) $(LIBS) internals/syslog.$(OBJEXT): internals/$(am__dirstamp) \ internals/$(DEPDIR)/$(am__dirstamp) test-syslog$(EXEEXT): $(test_syslog_OBJECTS) $(test_syslog_DEPENDENCIES) $(EXTRA_test_syslog_DEPENDENCIES) @rm -f test-syslog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_syslog_OBJECTS) $(test_syslog_LDADD) $(LIBS) test-uid-permissions$(EXEEXT): $(test_uid_permissions_OBJECTS) $(test_uid_permissions_DEPENDENCIES) $(EXTRA_test_uid_permissions_DEPENDENCIES) @rm -f test-uid-permissions$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_uid_permissions_OBJECTS) $(test_uid_permissions_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f internals/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/corrupt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-daemon-eavesdrop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-daemon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdpass.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loopback.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual-authz.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual-dir-iter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual-paths.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual-tcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/marshal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd-activation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shell-test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spawn-test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syntax.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-exit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-names.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-segfault.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-shell-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sleep-forever.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-utils-glib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uid-permissions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@internals/$(DEPDIR)/printf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@internals/$(DEPDIR)/refs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@internals/$(DEPDIR)/syslog.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-testmetaDATA: $(testmeta_DATA) @$(NORMAL_INSTALL) @list='$(testmeta_DATA)'; test -n "$(testmetadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(testmetadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(testmetadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(testmetadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(testmetadir)" || exit $$?; \ done uninstall-testmetaDATA: @$(NORMAL_UNINSTALL) @list='$(testmeta_DATA)'; test -n "$(testmetadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(testmetadir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? test-shell.log: test-shell$(EXEEXT) @p='test-shell$(EXEEXT)'; \ b='test-shell'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-printf.log: test-printf$(EXEEXT) @p='test-printf$(EXEEXT)'; \ b='test-printf'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-corrupt.log: test-corrupt$(EXEEXT) @p='test-corrupt$(EXEEXT)'; \ b='test-corrupt'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-dbus-daemon.log: test-dbus-daemon$(EXEEXT) @p='test-dbus-daemon$(EXEEXT)'; \ b='test-dbus-daemon'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-dbus-daemon-eavesdrop.log: test-dbus-daemon-eavesdrop$(EXEEXT) @p='test-dbus-daemon-eavesdrop$(EXEEXT)'; \ b='test-dbus-daemon-eavesdrop'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-fdpass.log: test-fdpass$(EXEEXT) @p='test-fdpass$(EXEEXT)'; \ b='test-fdpass'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-monitor.log: test-monitor$(EXEEXT) @p='test-monitor$(EXEEXT)'; \ b='test-monitor'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-loopback.log: test-loopback$(EXEEXT) @p='test-loopback$(EXEEXT)'; \ b='test-loopback'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-marshal.log: test-marshal$(EXEEXT) @p='test-marshal$(EXEEXT)'; \ b='test-marshal'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-refs.log: test-refs$(EXEEXT) @p='test-refs$(EXEEXT)'; \ b='test-refs'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-relay.log: test-relay$(EXEEXT) @p='test-relay$(EXEEXT)'; \ b='test-relay'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-syntax.log: test-syntax$(EXEEXT) @p='test-syntax$(EXEEXT)'; \ b='test-syntax'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-syslog.log: test-syslog$(EXEEXT) @p='test-syslog$(EXEEXT)'; \ b='test-syslog'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-uid-permissions.log: test-uid-permissions$(EXEEXT) @p='test-uid-permissions$(EXEEXT)'; \ b='test-uid-permissions'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-sd-activation.log: test-sd-activation$(EXEEXT) @p='test-sd-activation$(EXEEXT)'; \ b='test-sd-activation'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .sh.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.sh$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) all-local installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(testexecdir)" "$(DESTDIR)$(testmetadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f internals/$(DEPDIR)/$(am__dirstamp) -rm -f internals/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ clean-testexecPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) internals/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-data-local install-testmetaDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-testexecPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: installcheck-local maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) internals/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-testexecPROGRAMS uninstall-testmetaDATA .MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ check check-TESTS check-am clean clean-generic clean-libtool \ clean-local clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ clean-testexecPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-local install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip \ install-testexecPROGRAMS install-testmetaDATA installcheck \ installcheck-am installcheck-local installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am recheck tags tags-am uninstall \ uninstall-am uninstall-testexecPROGRAMS uninstall-testmetaDATA .PRECIOUS: Makefile @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@$(wrap_bus_tests): test-bus%.sh: ../bus/test-bus%$(EXEEXT) tap-test.sh.in Makefile @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ sed -e 's![@]RUN[@]!$ $@ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@$(wrap_dbus_tests): test-dbus%.sh: ../dbus/test-dbus%$(EXEEXT) tap-test.sh.in Makefile @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ sed -e 's![@]RUN[@]!$ $@ # If we're installing the tests into a DESTDIR we can't run them # again using the installed copy, because we don't know how to # do a portable equivalent of setting LD_LIBRARY_PATH. installcheck-local: $(MAKE) check-TESTS TESTS='$$(installcheck_tests)' \ AM_TESTS_ENVIRONMENT='$$(installcheck_environment)' @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ test -n "$(DESTDIR)" || { \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(installcheck_environment) \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(srcdir)/dbus-test-runner \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(testexecdir) \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(testexec_PROGRAMS) } all-local: copy-config-local uninstalled-config-local @: copy-config-local: $(AM_V_at)$(MKDIR_P) data/valid-config-files/session.d $(AM_V_GEN)set -e; \ if test $(srcdir) = . || test $(srcdir) -ef .; then \ echo '-- No need to copy test data as srcdir = builddir'; \ else \ for F in $(static_data); do \ $(MKDIR_P) "$${F%/*}"; \ rm -f "$$F"; \ cp $(srcdir)/"$$F" "$$F"; \ done; \ fi uninstalled-config-local: $(AM_V_GEN)set -e; \ for F in $(in_data); do \ $(MKDIR_P) "$${F%/*}"; \ sed \ -e 's,[@]DBUS_TEST_DATA[@],@abs_builddir@/data,' \ -e 's,[@]DBUS_TEST_EXEC[@],@abs_builddir@,' \ -e 's,[@]EXEEXT[@],$(EXEEXT),' \ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],@abs_top_builddir@/bus/dbus-daemon-launch-helper-test$(EXEEXT),' \ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \ < $(srcdir)/"$$F" > "$${F%.in}"; \ done installable-config-local: @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(AM_V_GEN)set -e; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ for F in $(in_data); do \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(MKDIR_P) "installable/$${F%/*}"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ sed \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ -e 's,[@]DBUS_TEST_DATA[@],$(testexecdir)/data,' \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ -e 's,[@]DBUS_TEST_EXEC[@],$(testexecdir),' \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ -e 's,[@]EXEEXT[@],$(EXEEXT),' \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],/bin/false,' \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ < $(srcdir)/"$$F" > "installable/$${F%.in}"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ done @DBUS_ENABLE_INSTALLED_TESTS_FALSE@ @: install-data-local: install-config-local @: install-config-local: installable-config-local @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ $(AM_V_GEN)set -e; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ for F in $(static_data); do \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ install -m644 "$(srcdir)/$$F" "$(DESTDIR)$(testexecdir)/$$F"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ done; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ for F in $(in_data); do \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ install -m644 "installable/$${F%.in}" "$(DESTDIR)$(testexecdir)/$${F%.in}"; \ @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ done @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ ln -nfs $(datadir)/dbus-1/session.conf $(DESTDIR)$(testexecdir)/data/valid-config-files/session.conf @DBUS_ENABLE_INSTALLED_TESTS_TRUE@ ln -nfs $(datadir)/dbus-1/system.conf $(DESTDIR)$(testexecdir)/data/valid-config-files-system/system.conf @DBUS_ENABLE_INSTALLED_TESTS_FALSE@ @: clean-local: $(AM_V_at)if test $(srcdir) = . || test $(srcdir) -ef .; then \ echo '-- No need to clean test data as srcdir = builddir'; \ else \ rm -f $(static_data); \ for F in $(in_data); do \ rm -f "$${F%.in}"; \ done; \ fi data/valid-config-files/session.conf: $(top_builddir)/bus/session.conf $(AM_V_at)$(MKDIR_P) data/valid-config-files $(AM_V_GEN)cp $< $@ data/valid-config-files-system/system.conf: $(top_builddir)/bus/system.conf $(AM_V_at)$(MKDIR_P) data/valid-config-files-system $(AM_V_GEN)cp $< $@ $(installable_test_meta): %.test: %$(EXEEXT) Makefile $(AM_V_GEN) ( \ echo '[Test]'; \ echo 'Type=session'; \ echo 'Output=TAP'; \ echo 'Exec=env $(testexecdir)/$* --tap'; \ ) > $@.tmp && mv $@.tmp $@ $(installable_test_meta_with_config): %_with_config.test: %$(EXEEXT) Makefile $(AM_V_GEN) ( \ echo '[Test]'; \ echo 'Type=session'; \ echo 'Output=TAP'; \ echo 'Exec=env DBUS_TEST_DATA=$(testexecdir)/data $(testexecdir)/$* --tap'; \ ) > $@.tmp && mv $@.tmp $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dbus-1.10.6/test/Makefile.am0000644000175000017500000003734212627362053015570 0ustar00smcvsmcv00000000000000## the "name-test" subdir in fact contains a bunch of tests now that need a temporary bus ## to be running to do stuff with. The directory should be renamed. ## We want to build the current directory first to pick up the testutils lib SUBDIRS= . name-test DIST_SUBDIRS=name-test CLEANFILES = EXTRA_DIST = AM_CPPFLAGS = \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ -DDBUS_COMPILATION \ $(GLIB_CFLAGS) \ $(NULL) # improve backtraces from test stuff AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ noinst_LTLIBRARIES = libdbus-testutils.la libdbus_testutils_la_SOURCES = \ test-utils.c \ test-utils.h \ $(NULL) if DBUS_WITH_GLIB libdbus_testutils_la_SOURCES += \ test-utils-glib.c \ test-utils-glib.h \ $(NULL) endif libdbus_testutils_la_LIBADD = \ $(top_builddir)/dbus/libdbus-1.la \ $(top_builddir)/dbus/libdbus-internal.la \ $(NULL) TEST_EXTENSIONS = .sh LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh LOG_COMPILER = $(srcdir)/glib-tap-test.sh SH_LOG_DRIVER = $(LOG_DRIVER) SH_LOG_COMPILER = $(SHELL) EXTRA_DIST += glib-tap-test.sh EXTRA_DIST += tap-test.sh.in TESTS = if DBUS_ENABLE_EMBEDDED_TESTS ## break-loader removed for now ## these binaries are used in tests but are not themselves tests TEST_BINARIES = \ test-spawn \ test-exit \ test-names \ test-segfault \ test-service \ test-shell-service \ test-sleep-forever \ $(NULL) ## These are conceptually part of directories that come earlier in SUBDIRS ## order, but we don't want to run them til we arrive in this directory, ## since they depend on stuff from this directory. We wrap them in a ## simple shell script to get TAP output. wrap_bus_tests = test-bus.sh wrap_dbus_tests = test-dbus.sh if DBUS_UNIX wrap_bus_tests += test-bus-launch-helper.sh wrap_bus_tests += test-bus-system.sh endif TESTS += $(wrap_bus_tests) $(wrap_dbus_tests) CLEANFILES += $(wrap_bus_tests) $(wrap_dbus_tests) $(wrap_bus_tests): test-bus%.sh: ../bus/test-bus%$(EXEEXT) tap-test.sh.in Makefile sed -e 's![@]RUN[@]!$ $@ $(wrap_dbus_tests): test-dbus%.sh: ../dbus/test-dbus%$(EXEEXT) tap-test.sh.in Makefile sed -e 's![@]RUN[@]!$ $@ else !DBUS_ENABLE_EMBEDDED_TESTS TEST_BINARIES= endif !DBUS_ENABLE_EMBEDDED_TESTS noinst_PROGRAMS= $(TEST_BINARIES) test_service_LDADD = libdbus-testutils.la test_names_LDADD = libdbus-testutils.la ## break_loader_LDADD = $(top_builddir)/dbus/libdbus-internal.la test_shell_service_LDADD = libdbus-testutils.la test_shell_SOURCES = shell-test.c test_shell_LDADD = libdbus-testutils.la test_spawn_SOURCES = spawn-test.c test_spawn_LDADD = $(top_builddir)/dbus/libdbus-internal.la test_printf_SOURCES = internals/printf.c test_printf_LDADD = $(top_builddir)/dbus/libdbus-internal.la test_refs_SOURCES = internals/refs.c test_refs_LDADD = libdbus-testutils.la $(GLIB_LIBS) test_syslog_SOURCES = internals/syslog.c test_syslog_LDADD = libdbus-testutils.la $(GLIB_LIBS) manual_dir_iter_SOURCES = manual-dir-iter.c manual_dir_iter_LDADD = $(top_builddir)/dbus/libdbus-internal.la manual_paths_SOURCES = manual-paths.c manual_paths_LDADD = $(top_builddir)/dbus/libdbus-internal.la manual_tcp_SOURCES = manual-tcp.c manual_tcp_LDADD = $(top_builddir)/dbus/libdbus-internal.la EXTRA_DIST += dbus-test-runner testexecdir = $(libexecdir)/installed-tests/dbus testmetadir = $(datadir)/installed-tests/dbus testexec_PROGRAMS = testmeta_DATA = installable_tests = \ test-shell \ test-printf \ $(NULL) installable_manual_tests = \ manual-dir-iter \ manual-tcp \ $(NULL) if DBUS_WIN installable_manual_tests += manual-paths endif if DBUS_WITH_GLIB installable_tests += \ test-corrupt \ test-dbus-daemon \ test-dbus-daemon-eavesdrop \ test-fdpass \ test-monitor \ test-loopback \ test-marshal \ test-refs \ test-relay \ test-syntax \ test-syslog \ test-uid-permissions \ $(NULL) if DBUS_UNIX installable_tests += \ test-sd-activation \ $(NULL) endif DBUS_UNIX installable_manual_tests += \ manual-authz \ $(NULL) endif DBUS_WITH_GLIB installable_test_meta = $(installable_tests:=.test) installable_test_meta_with_config = $(installable_tests:=_with_config.test) installcheck_tests = installcheck_environment = \ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ export DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT); \ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \ export DBUS_TEST_DATADIR=$(DESTDIR)$(datadir); \ ${NULL} AM_TESTS_ENVIRONMENT = \ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ export DBUS_FATAL_WARNINGS=1; \ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \ export DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus; \ $(NULL) manual_authz_SOURCES = manual-authz.c manual_authz_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_corrupt_SOURCES = corrupt.c test_corrupt_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_loopback_SOURCES = loopback.c test_loopback_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_relay_SOURCES = relay.c test_relay_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_dbus_daemon_SOURCES = dbus-daemon.c test_dbus_daemon_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_dbus_daemon_eavesdrop_SOURCES = dbus-daemon-eavesdrop.c test_dbus_daemon_eavesdrop_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) if DBUS_UNIX test_sd_activation_SOURCES = \ sd-activation.c \ $(NULL) test_sd_activation_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) endif test_marshal_SOURCES = marshal.c test_marshal_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_monitor_SOURCES = \ monitor.c \ $(NULL) test_monitor_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_syntax_SOURCES = syntax.c test_syntax_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_uid_permissions_SOURCES = \ uid-permissions.c \ $(NULL) test_uid_permissions_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) test_fdpass_SOURCES = \ fdpass.c \ $(NULL) test_fdpass_LDADD = \ libdbus-testutils.la \ $(GLIB_LIBS) \ $(NULL) if DBUS_ENABLE_MODULAR_TESTS TESTS += $(installable_tests) installcheck_tests += $(installable_tests) if DBUS_ENABLE_INSTALLED_TESTS testexec_PROGRAMS += $(installable_tests) $(installable_manual_tests) testmeta_DATA += $(installable_test_meta) testmeta_DATA += $(installable_test_meta_with_config) else !DBUS_ENABLE_INSTALLED_TESTS noinst_PROGRAMS += $(installable_tests) $(installable_manual_tests) endif !DBUS_ENABLE_INSTALLED_TESTS endif DBUS_ENABLE_MODULAR_TESTS # If we're installing the tests into a DESTDIR we can't run them # again using the installed copy, because we don't know how to # do a portable equivalent of setting LD_LIBRARY_PATH. installcheck-local: $(MAKE) check-TESTS TESTS='$$(installcheck_tests)' \ AM_TESTS_ENVIRONMENT='$$(installcheck_environment)' if DBUS_ENABLE_INSTALLED_TESTS test -n "$(DESTDIR)" || { \ $(installcheck_environment) \ $(srcdir)/dbus-test-runner \ $(testexecdir) \ $(testexec_PROGRAMS) } endif DBUS_ENABLE_INSTALLED_TESTS in_data = \ data/valid-config-files-system/debug-allow-all-fail.conf.in \ data/valid-config-files-system/debug-allow-all-pass.conf.in \ data/valid-config-files/debug-allow-all-sha1.conf.in \ data/valid-config-files/debug-allow-all.conf.in \ data/valid-config-files/finite-timeout.conf.in \ data/valid-config-files/forbidding.conf.in \ data/valid-config-files/incoming-limit.conf.in \ data/valid-config-files/multi-user.conf.in \ data/valid-config-files/systemd-activation.conf.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ $(NULL) EXTRA_DIST += $(in_data) static_data = \ name-test/tmp-session-like-system.conf \ data/auth/anonymous-client-successful.auth-script \ data/auth/anonymous-server-successful.auth-script \ data/auth/cancel.auth-script \ data/auth/client-out-of-mechanisms.auth-script \ data/auth/external-failed.auth-script \ data/auth/external-root.auth-script \ data/auth/external-silly.auth-script \ data/auth/external-successful.auth-script \ data/auth/extra-bytes.auth-script \ data/auth/fail-after-n-attempts.auth-script \ data/auth/fallback.auth-script \ data/auth/invalid-command-client.auth-script \ data/auth/invalid-command.auth-script \ data/auth/invalid-hex-encoding.auth-script \ data/auth/mechanisms.auth-script \ data/equiv-config-files/basic/basic-1.conf \ data/equiv-config-files/basic/basic-2.conf \ data/equiv-config-files/basic/basic.d/basic.conf \ data/equiv-config-files/entities/basic.d/basic.conf \ data/equiv-config-files/entities/entities-1.conf \ data/equiv-config-files/entities/entities-2.conf \ data/incomplete-messages/missing-body.message \ data/invalid-config-files/badselinux-1.conf \ data/invalid-config-files/badselinux-2.conf \ data/invalid-config-files/circular-1.conf \ data/invalid-config-files/circular-2.conf \ data/invalid-config-files/circular-3.conf \ data/invalid-config-files/not-well-formed.conf \ data/invalid-config-files/truncated-file.conf \ data/invalid-messages/array-of-nil.message \ data/invalid-messages/array-with-mixed-types.message \ data/invalid-messages/bad-boolean-array.message \ data/invalid-messages/bad-boolean.message \ data/invalid-messages/bad-endian.message \ data/invalid-messages/bad-header-field-alignment.message \ data/invalid-messages/boolean-has-no-value.message-raw \ data/invalid-messages/local-namespace.message \ data/invalid-messages/no-dot-in-name.message \ data/invalid-messages/not-nul-header-padding.message \ data/invalid-messages/overlong-name.message \ data/invalid-messages/too-little-header-padding.message \ data/invalid-messages/too-much-header-padding-by-far.message \ data/invalid-messages/too-much-header-padding.message \ data/invalid-messages/too-short-dict.message \ data/sha-1/Readme.txt \ data/sha-1/bit-hashes.sha1 \ data/sha-1/bit-messages.sha1 \ data/sha-1/byte-hashes.sha1 \ data/sha-1/byte-messages.sha1 \ data/systemd-activation/com.example.SystemdActivatable1.service \ data/systemd-activation/com.example.SystemdActivatable2.service \ data/systemd-activation/com.example.SystemdActivatable3.service \ data/systemd-activation/org.freedesktop.systemd1.service \ data/valid-config-files/basic.conf \ data/valid-config-files/basic.d/basic.conf \ data/valid-config-files/entities.conf \ data/valid-config-files/listen-unix-runtime.conf \ data/valid-config-files/many-rules.conf \ data/valid-config-files-system/system.d/test.conf \ data/valid-messages/array-of-array-of-uint32.message \ data/valid-messages/dict-simple.message \ data/valid-messages/dict.message \ data/valid-messages/emptiness.message \ data/valid-messages/lots-of-arguments.message \ data/valid-messages/no-padding.message \ data/valid-messages/opposite-endian.message \ data/valid-messages/recursive-types.message \ data/valid-messages/simplest-manual.message \ data/valid-messages/simplest.message \ data/valid-messages/standard-acquire-service.message \ data/valid-messages/standard-hello.message \ data/valid-messages/standard-list-services.message \ data/valid-messages/standard-service-exists.message \ data/valid-messages/unknown-header-field.message \ $(NULL) EXTRA_DIST += $(static_data) ## copy tests to builddir so that generated tests and static tests ## are all in one place. all-local: copy-config-local uninstalled-config-local @: copy-config-local: $(AM_V_at)$(MKDIR_P) data/valid-config-files/session.d $(AM_V_GEN)set -e; \ if test $(srcdir) = . || test $(srcdir) -ef .; then \ echo '-- No need to copy test data as srcdir = builddir'; \ else \ for F in $(static_data); do \ $(MKDIR_P) "$${F%/*}"; \ rm -f "$$F"; \ cp $(srcdir)/"$$F" "$$F"; \ done; \ fi uninstalled-config-local: $(AM_V_GEN)set -e; \ for F in $(in_data); do \ $(MKDIR_P) "$${F%/*}"; \ sed \ -e 's,[@]DBUS_TEST_DATA[@],@abs_builddir@/data,' \ -e 's,[@]DBUS_TEST_EXEC[@],@abs_builddir@,' \ -e 's,[@]EXEEXT[@],$(EXEEXT),' \ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],@abs_top_builddir@/bus/dbus-daemon-launch-helper-test$(EXEEXT),' \ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \ < $(srcdir)/"$$F" > "$${F%.in}"; \ done installable-config-local: if DBUS_ENABLE_INSTALLED_TESTS $(AM_V_GEN)set -e; \ for F in $(in_data); do \ $(MKDIR_P) "installable/$${F%/*}"; \ sed \ -e 's,[@]DBUS_TEST_DATA[@],$(testexecdir)/data,' \ -e 's,[@]DBUS_TEST_EXEC[@],$(testexecdir),' \ -e 's,[@]EXEEXT[@],$(EXEEXT),' \ -e 's,[@]TEST_LAUNCH_HELPER_BINARY[@],/bin/false,' \ -e 's,[@]TEST_LISTEN[@],$(TEST_LISTEN),' \ < $(srcdir)/"$$F" > "installable/$${F%.in}"; \ done else @: endif install-data-local: install-config-local @: install-config-local: installable-config-local if DBUS_ENABLE_INSTALLED_TESTS $(AM_V_GEN)set -e; \ for F in $(static_data); do \ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \ install -m644 "$(srcdir)/$$F" "$(DESTDIR)$(testexecdir)/$$F"; \ done; \ for F in $(in_data); do \ install -d "$(DESTDIR)$(testexecdir)/$${F%/*}"; \ install -m644 "installable/$${F%.in}" "$(DESTDIR)$(testexecdir)/$${F%.in}"; \ done ln -nfs $(datadir)/dbus-1/session.conf $(DESTDIR)$(testexecdir)/data/valid-config-files/session.conf ln -nfs $(datadir)/dbus-1/system.conf $(DESTDIR)$(testexecdir)/data/valid-config-files-system/system.conf else @: endif ## this doesn't clean most copied test data files when srcdir=builddir clean-local: $(AM_V_at)if test $(srcdir) = . || test $(srcdir) -ef .; then \ echo '-- No need to clean test data as srcdir = builddir'; \ else \ rm -f $(static_data); \ for F in $(in_data); do \ rm -f "$${F%.in}"; \ done; \ fi imported_data = \ data/valid-config-files/session.conf \ data/valid-config-files-system/system.conf \ $(NULL) noinst_DATA = $(imported_data) CLEANFILES += \ $(noinst_DATA) \ XDG_RUNTIME_DIR \ installable \ $(NULL) data/valid-config-files/session.conf: $(top_builddir)/bus/session.conf $(AM_V_at)$(MKDIR_P) data/valid-config-files $(AM_V_GEN)cp $< $@ data/valid-config-files-system/system.conf: $(top_builddir)/bus/system.conf $(AM_V_at)$(MKDIR_P) data/valid-config-files-system $(AM_V_GEN)cp $< $@ $(installable_test_meta): %.test: %$(EXEEXT) Makefile $(AM_V_GEN) ( \ echo '[Test]'; \ echo 'Type=session'; \ echo 'Output=TAP'; \ echo 'Exec=env $(testexecdir)/$* --tap'; \ ) > $@.tmp && mv $@.tmp $@ $(installable_test_meta_with_config): %_with_config.test: %$(EXEEXT) Makefile $(AM_V_GEN) ( \ echo '[Test]'; \ echo 'Type=session'; \ echo 'Output=TAP'; \ echo 'Exec=env DBUS_TEST_DATA=$(testexecdir)/data $(testexecdir)/$* --tap'; \ ) > $@.tmp && mv $@.tmp $@ dbus-1.10.6/test/name-test/0000755000175000017500000000000012627367774015437 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/name-test/test-activation-forking.py0000644000175000017500000000337012602773110022541 0ustar00smcvsmcv00000000000000#!/usr/bin/env python import os,sys try: from gi.repository import GObject import dbus import dbus.mainloop.glib except: print "Failed import, aborting test" sys.exit(0) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) loop = GObject.MainLoop() exitcode = 0 bus = dbus.SessionBus() bus_iface = dbus.Interface(bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus'), 'org.freedesktop.DBus') o = bus.get_object('org.freedesktop.DBus.TestSuiteForkingEchoService', '/org/freedesktop/TestSuite') i = dbus.Interface(o, 'org.freedesktop.TestSuite') # Start it up reply = i.Echo("hello world") print "TestSuiteForkingEchoService initial reply OK" def ignore(*args, **kwargs): pass # Now monitor for exits, when that happens, start it up again. # The goal here is to try to hit any race conditions in activation. counter = 0 def on_forking_echo_owner_changed(name, old, new): global counter global o global i if counter > 10: print "Activated 10 times OK, TestSuiteForkingEchoService pass" loop.quit() return counter += 1 if new == '': o = bus.get_object('org.freedesktop.DBus.TestSuiteForkingEchoService', '/org/freedesktop/TestSuite') i = dbus.Interface(o, 'org.freedesktop.TestSuite') i.Echo("counter %r" % counter) i.Exit(reply_handler=ignore, error_handler=ignore) bus_iface.connect_to_signal('NameOwnerChanged', on_forking_echo_owner_changed, arg0='org.freedesktop.DBus.TestSuiteForkingEchoService') i.Exit(reply_handler=ignore, error_handler=ignore) def check_counter(): if counter == 0: print "Failed to get NameOwnerChanged for TestSuiteForkingEchoService" sys.exit(1) GObject.timeout_add(15000, check_counter) loop.run() sys.exit(0) dbus-1.10.6/test/name-test/test-wait-for-echo.py0000755000175000017500000000164012602773110021410 0ustar00smcvsmcv00000000000000#!/usr/bin/env python import os,sys try: import dbus import dbus.mainloop.glib from gi.repository import GObject except: print "Failed import, aborting test" sys.exit(0) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) loop = GObject.MainLoop() exitcode = 0 def handle_noreceipt(): print "Failed to get signal" global exitcode exitcode = 1 loop.quit() GObject.timeout_add(7000, handle_noreceipt) bus = dbus.SessionBus() def sighandler(*args, **kwargs): print "got signal" loop.quit() bus.add_signal_receiver(sighandler, dbus_interface='org.freedesktop.TestSuite', signal_name='Foo') o = bus.get_object('org.freedesktop.DBus.TestSuiteEchoService', '/org/freedesktop/TestSuite') i = dbus.Interface(o, 'org.freedesktop.TestSuite') def nullhandler(*args, **kwargs): pass i.EmitFoo(reply_handler=nullhandler, error_handler=nullhandler) loop.run() sys.exit(exitcode) dbus-1.10.6/test/name-test/run-test-systemserver.sh0000755000175000017500000000460112602773110022303 0ustar00smcvsmcv00000000000000#! /bin/sh SCRIPTNAME=$0 MODE=$1 ## so the tests can complain if you fail to use the script to launch them DBUS_TEST_NAME_RUN_TEST_SCRIPT=1 export DBUS_TEST_NAME_RUN_TEST_SCRIPT SOURCE_CONFIG_FILE=$DBUS_TOP_SRCDIR/test/name-test/tmp-session-like-system.conf export SOURCE_CONFIG_FILE # Rerun ourselves with tmp session bus if we're not already if test -z "$DBUS_TEST_NAME_IN_SYS_RUN_TEST"; then DBUS_TEST_NAME_IN_SYS_RUN_TEST=1 export DBUS_TEST_NAME_IN_SYS_RUN_TEST exec $DBUS_TOP_SRCDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE fi if test -n "$DBUS_TEST_MONITOR"; then dbus-monitor --session >&2 & fi XDG_RUNTIME_DIR="$DBUS_TOP_BUILDDIR"/test/XDG_RUNTIME_DIR test -d "$XDG_RUNTIME_DIR" || mkdir "$XDG_RUNTIME_DIR" chmod 0700 "$XDG_RUNTIME_DIR" export XDG_RUNTIME_DIR # Translate a command and exit status into TAP syntax. # Usage: interpret_result $? description-of-test # Uses global variable $test_num. interpret_result () { e="$1" shift case "$e" in (0) echo "ok $test_num $*" ;; (77) echo "ok $test_num # SKIP $*" ;; (*) echo "not ok $test_num $*" ;; esac test_num=$(( $test_num + 1 )) } dbus_send_test () { t="$1" expected_exit="$2" phrase="$3" shift 3 e=0 echo "# running test $t" "${DBUS_TOP_BUILDDIR}/libtool" --mode=execute $DEBUG "$DBUS_TOP_BUILDDIR/tools/dbus-send" "$@" > output.tmp 2>&1 || e=$? if [ $e != $expected_exit ]; then sed -e 's/^/# /' < output.tmp interpret_result "1" "$t" "$@" "(expected exit status $expected_exit, got $e)" return fi echo "# parsing results of test $t" if ! grep -q "$phrase" output.tmp; then sed -e 's/^/# /' < output.tmp interpret_result "1" "$t" "$@" "(Did not see \"$phrase\" in output)" return fi interpret_result "0" "$t" "$@" "(Saw \"$phrase\" in output as expected)" rm -f output.tmp } py_test () { t="$1" shift if test "x$PYTHON" = "x:"; then interpret_result 77 "$t" "(Python interpreter not found)" else e=0 echo "# running test $t" $PYTHON "$DBUS_TOP_SRCDIR/test/name-test/$t" "$@" >&2 || e=$? interpret_result "$e" "$t" "$@" fi } test_num=1 # TAP syntax: we plan to run 2 tests echo "1..2" dbus_send_test test-expected-echo-fail 1 DBus.Error --print-reply --dest=org.freedesktop.DBus.TestSuiteEchoService /org/freedesktop/TestSuite org.freedesktop.TestSuite.Echo string:hi py_test test-wait-for-echo.py dbus-1.10.6/test/name-test/run-test.sh0000755000175000017500000000352112602773110017532 0ustar00smcvsmcv00000000000000#! /bin/sh SCRIPTNAME=$0 MODE=$1 ## so the tests can complain if you fail to use the script to launch them DBUS_TEST_NAME_RUN_TEST_SCRIPT=1 export DBUS_TEST_NAME_RUN_TEST_SCRIPT # Rerun ourselves with tmp session bus if we're not already if test -z "$DBUS_TEST_NAME_IN_RUN_TEST"; then DBUS_TEST_NAME_IN_RUN_TEST=1 export DBUS_TEST_NAME_IN_RUN_TEST exec $DBUS_TOP_SRCDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE fi if test -n "$DBUS_TEST_MONITOR"; then dbus-monitor --session >&2 & fi XDG_RUNTIME_DIR="$DBUS_TOP_BUILDDIR"/test/XDG_RUNTIME_DIR test -d "$XDG_RUNTIME_DIR" || mkdir "$XDG_RUNTIME_DIR" chmod 0700 "$XDG_RUNTIME_DIR" export XDG_RUNTIME_DIR # Translate a command and exit status into TAP syntax. # Usage: interpret_result $? description-of-test # Uses global variable $test_num. interpret_result () { e="$1" shift case "$e" in (0) echo "ok $test_num $*" ;; (77) echo "ok $test_num # SKIP $*" ;; (*) echo "not ok $test_num $*" ;; esac test_num=$(( $test_num + 1 )) } c_test () { t="$1" shift e=0 echo "# running test $t" if ! "${DBUS_TOP_BUILDDIR}/libtool" --mode=execute $DEBUG "$DBUS_TOP_BUILDDIR/test/name-test/$t" "$@" >&2; then e=$? echo "# exit status $e" fi interpret_result "$e" "$t" "$@" } py_test () { t="$1" shift if test "x$PYTHON" = "x:"; then interpret_result 77 "$t" "(Python interpreter not found)" else e=0 echo "# running test $t" $PYTHON "$DBUS_TOP_SRCDIR/test/name-test/$t" "$@" >&2 || e=$? interpret_result "$e" "$t" "$@" fi } test_num=1 # TAP test plan: we will run 8 tests echo "1..8" c_test test-ids c_test test-pending-call-dispatch c_test test-pending-call-timeout c_test test-threads-init c_test test-privserver-client c_test test-shutdown py_test test-activation-forking.py c_test test-autolaunch dbus-1.10.6/test/name-test/test-threads-init.c0000644000175000017500000001247412602773110021135 0ustar00smcvsmcv00000000000000/** * Test to make sure late thread initialization works */ #include #include #include #include #include #include #include static void _run_iteration (DBusConnection *conn) { DBusPendingCall *echo_pending; DBusPendingCall *dbus_pending; DBusMessage *method; DBusMessage *reply; char *echo = "echo"; /* send the first message */ method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Echo"); dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); dbus_connection_send_with_reply (conn, method, &echo_pending, -1); dbus_message_unref (method); /* send the second message */ method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.Introspectable", "Introspect"); dbus_connection_send_with_reply (conn, method, &dbus_pending, -1); dbus_message_unref (method); /* block on the second message (should return immediately) */ dbus_pending_call_block (dbus_pending); /* block on the first message */ /* if it does not return immediately chances are we hit the block in poll bug */ dbus_pending_call_block (echo_pending); /* check the reply only to make sure we are not getting errors unrelated to the block in poll bug */ reply = dbus_pending_call_steal_reply (echo_pending); if (reply == NULL) { printf ("Failed: Reply is NULL ***\n"); exit (1); } if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); exit (1); } dbus_message_unref (reply); dbus_pending_call_unref (dbus_pending); dbus_pending_call_unref (echo_pending); } static void check_mutex_lock (DBusMutex *mutex1, DBusMutex *mutex2, dbus_bool_t is_same) { _dbus_assert (mutex1 != NULL); _dbus_assert (mutex2 != NULL); if (is_same) { _dbus_assert (mutex1 == mutex2); } else { _dbus_assert (mutex1 != mutex2); } } static void check_condvar_lock (DBusCondVar *condvar1, DBusCondVar *condvar2, dbus_bool_t is_same) { _dbus_assert (condvar1 != NULL); _dbus_assert (condvar2 != NULL); if (is_same) { _dbus_assert (condvar1 == condvar2); } else { _dbus_assert (condvar1 != condvar2); } } int main (int argc, char *argv[]) { DBusMessage *method; DBusConnection *conn; DBusError error; DBusMutex *mutex1, *dispatch_mutex1, *io_path_mutex1; DBusCondVar *dispatch_cond1, *io_path_cond1; DBusMutex *mutex2, *dispatch_mutex2, *io_path_mutex2; DBusCondVar *dispatch_cond2, *io_path_cond2; printf ("*** Testing late thread init\n"); dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); _dbus_connection_test_get_locks (conn, &mutex1, &dispatch_mutex1, &io_path_mutex1, &dispatch_cond1, &io_path_cond1); _run_iteration (conn); _dbus_connection_test_get_locks (conn, &mutex2, &dispatch_mutex2, &io_path_mutex2, &dispatch_cond2, &io_path_cond2); check_mutex_lock (mutex1, mutex2, TRUE); check_mutex_lock (dispatch_mutex1, dispatch_mutex2, TRUE); check_mutex_lock (io_path_mutex1, io_path_mutex2, TRUE); check_condvar_lock (dispatch_cond1, dispatch_cond2, TRUE); check_condvar_lock (io_path_cond1, io_path_cond2, TRUE); dbus_threads_init_default (); _dbus_connection_test_get_locks (conn, &mutex1, &dispatch_mutex1, &io_path_mutex1, &dispatch_cond1, &io_path_cond1); _run_iteration (conn); _dbus_connection_test_get_locks (conn, &mutex2, &dispatch_mutex2, &io_path_mutex2, &dispatch_cond2, &io_path_cond2); check_mutex_lock (mutex1, mutex2, TRUE); check_mutex_lock (dispatch_mutex1, dispatch_mutex2, TRUE); check_mutex_lock (io_path_mutex1, io_path_mutex2, TRUE); check_condvar_lock (dispatch_cond1, dispatch_cond2, TRUE); check_condvar_lock (io_path_cond1, io_path_cond2, TRUE); method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Exit"); dbus_connection_send (conn, method, NULL); dbus_message_unref (method); printf ("Success ***\n"); exit (0); } dbus-1.10.6/test/name-test/test-shutdown.c0000644000175000017500000000252712602773110020413 0ustar00smcvsmcv00000000000000 #include #include "../test-utils.h" static DBusLoop *loop; static void die (const char *message) { fprintf (stderr, "*** test-shutdown: %s", message); exit (1); } static void open_destroy_shared_session_bus_connection (void) { DBusError error; DBusConnection *connection; char *session_addr_no_guid; char *comma; dbus_error_init (&error); session_addr_no_guid = strdup (getenv ("DBUS_SESSION_BUS_ADDRESS")); comma = strchr (session_addr_no_guid, ','); if (comma == NULL) die ("Couldn't find GUID in session bus address"); *comma = '\0'; connection = dbus_connection_open (session_addr_no_guid, &error); free (session_addr_no_guid); if (connection == NULL) die ("Failed to open connection to temp session bus\n"); loop = _dbus_loop_new (); if (loop == NULL) die ("No memory\n"); if (!test_connection_setup (loop, connection)) die ("No memory\n"); test_connection_shutdown (loop, connection); _dbus_loop_unref (loop); dbus_connection_unref (connection); } int main (int argc, char **argv) { open_destroy_shared_session_bus_connection (); dbus_shutdown (); open_destroy_shared_session_bus_connection (); dbus_shutdown (); open_destroy_shared_session_bus_connection (); dbus_shutdown (); _dbus_verbose ("*** Test shutdown exiting\n"); return 0; } dbus-1.10.6/test/name-test/test-privserver-client.c0000644000175000017500000001212012602773110022211 0ustar00smcvsmcv00000000000000#include #include "../test-utils.h" static void die (const char *message, ...) { va_list args; va_start (args, message); vfprintf (stderr, message, args); va_end (args); exit (1); } #define PRIVSERVER_SERVICE "org.freedesktop.DBus.TestSuite.PrivServer" #define PRIVSERVER_INTERFACE PRIVSERVER_SERVICE #define PRIVSERVER_DIED_RULE \ "type='signal',sender='" DBUS_SERVICE_DBUS "'," \ "interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," \ "arg0='" PRIVSERVER_SERVICE "',arg2=''" static DBusHandlerResult filter_session_message (DBusConnection *connection, DBusMessage *message, void *user_data) { dbus_bool_t *service_died_p = user_data; const char *name, *old_owner, *new_owner; if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged") && dbus_message_has_sender (message, DBUS_SERVICE_DBUS) && dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID) && strcmp (name, PRIVSERVER_SERVICE) == 0 && old_owner[0] != '\0' && new_owner[0] == '\0') { *service_died_p = TRUE; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult filter_private_message (DBusConnection *connection, DBusMessage *message, void *user_data) { dbus_bool_t *private_conn_lost_p = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { *private_conn_lost_p = TRUE; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void open_shutdown_private_connection (dbus_bool_t use_guid) { DBusError error; DBusLoop *loop; DBusConnection *session; DBusMessage *msg; DBusMessage *reply; DBusConnection *privconn; char *addr; dbus_bool_t service_died; dbus_bool_t private_conn_lost; dbus_error_init (&error); service_died = FALSE; private_conn_lost = FALSE; loop = _dbus_loop_new (); session = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!session) die ("couldn't access session bus\n"); dbus_connection_set_exit_on_disconnect (session, FALSE); test_connection_setup (loop, session); dbus_bus_add_match (session, PRIVSERVER_DIED_RULE, &error); if (dbus_error_is_set (&error)) die ("couldn't add match rule \"%s\": %s: %s", PRIVSERVER_DIED_RULE, error.name, error.message); if (!dbus_connection_add_filter (session, filter_session_message, &service_died, NULL)) die ("couldn't add filter to session bus\n"); msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/", PRIVSERVER_INTERFACE, "GetPrivateAddress"); if (!(reply = dbus_connection_send_with_reply_and_block (session, msg, -1, &error))) die ("couldn't send message: %s\n", error.message); dbus_message_unref (msg); if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &addr, DBUS_TYPE_INVALID)) die ("couldn't parse message replym\n"); printf ("got private temp address %s\n", addr); addr = strdup (addr); if (!use_guid) { char *comma = strrchr (addr, ','); if (comma) *comma = '\0'; } privconn = dbus_connection_open (addr, &error); free (addr); if (!privconn) die ("couldn't connect to server direct connection: %s\n", error.message); dbus_message_unref (reply); dbus_connection_set_exit_on_disconnect (privconn, FALSE); if (!dbus_connection_add_filter (privconn, filter_private_message, &private_conn_lost, NULL)) die ("couldn't add filter to private connection\n"); test_connection_setup (loop, privconn); msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/", PRIVSERVER_INTERFACE, "Quit"); if (!dbus_connection_send (session, msg, NULL)) die ("couldn't send Quit message\n"); dbus_message_unref (msg); while (!service_died || !private_conn_lost) _dbus_loop_iterate (loop, TRUE); dbus_connection_remove_filter (session, filter_session_message, &service_died); dbus_bus_remove_match (session, PRIVSERVER_DIED_RULE, NULL); test_connection_shutdown (loop, session); dbus_connection_unref (session); test_connection_shutdown (loop, privconn); dbus_connection_remove_filter (privconn, filter_private_message, &private_conn_lost); dbus_connection_unref (privconn); _dbus_loop_unref (loop); } int main (int argc, char *argv[]) { open_shutdown_private_connection (TRUE); dbus_shutdown (); open_shutdown_private_connection (TRUE); dbus_shutdown (); open_shutdown_private_connection (FALSE); dbus_shutdown (); open_shutdown_private_connection (FALSE); dbus_shutdown (); return 0; } dbus-1.10.6/test/name-test/test-privserver.c0000644000175000017500000000643012602773110020744 0ustar00smcvsmcv00000000000000#include #include "../test-utils.h" static void die (const char *message, ...) { va_list args; va_start (args, message); vfprintf (stderr, message, args); va_end (args); exit (1); } typedef struct TestServiceData TestServiceData; struct TestServiceData { DBusLoop *loop; char *private_addr; }; static void new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *data) { TestServiceData *testdata = data; if (!test_connection_setup (testdata->loop, new_connection)) dbus_connection_close (new_connection); } static DBusHandlerResult filter_session_message (DBusConnection *connection, DBusMessage *message, void *user_data) { TestServiceData *testdata = user_data; if (dbus_message_is_method_call (message, "org.freedesktop.DBus.TestSuite.PrivServer", "GetPrivateAddress")) { DBusMessage *reply; reply = dbus_message_new_method_return (message); dbus_message_append_args (reply, DBUS_TYPE_STRING, &(testdata->private_addr), DBUS_TYPE_INVALID); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.TestSuite.PrivServer", "Quit")) { fprintf (stderr, "server exiting loop\n"); _dbus_loop_quit (testdata->loop); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } int main (int argc, char *argv[]) { DBusServer *server; DBusError error; DBusLoop *loop; DBusConnection *session; TestServiceData *testdata; dbus_error_init (&error); loop = _dbus_loop_new (); testdata = dbus_new (TestServiceData, 1); testdata->loop = loop; session = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!session) die ("couldn't access session bus"); test_connection_setup (loop, session); dbus_bus_request_name (session, "org.freedesktop.DBus.TestSuite.PrivServer", 0, &error); if (dbus_error_is_set (&error)) die ("couldn't request name: %s", error.message); if (!dbus_connection_add_filter (session, filter_session_message, testdata, NULL)) die ("couldn't add filter"); #ifdef DBUS_CMAKE server = dbus_server_listen (TEST_LISTEN, &error); #else server = dbus_server_listen ("unix:tmpdir=/tmp", &error); #endif if (!server) die (error.message); testdata->private_addr = dbus_server_get_address (server); printf ("test server listening on %s\n", testdata->private_addr); dbus_server_set_new_connection_function (server, new_connection_callback, testdata, NULL); if (!test_server_setup (loop, server)) die ("server setup failed"); fprintf (stderr, "server running mainloop\n"); _dbus_loop_run (loop); fprintf (stderr, "server mainloop quit\n"); test_server_shutdown (loop, server); test_connection_shutdown (loop, session); dbus_connection_unref (session); _dbus_loop_unref (loop); dbus_free (testdata); return 0; } dbus-1.10.6/test/name-test/test-pending-call-timeout.c0000644000175000017500000000525712602773110022564 0ustar00smcvsmcv00000000000000/** * Test to make sure that pending calls succeed when given a default, * specific and infinite timeout. **/ #include #include #include #include #include #include static void _method_call (DBusConnection *conn, int timeout_milliseconds) { DBusPendingCall *pending; DBusMessage *method; DBusMessage *reply; char *echo = "echo"; /* send the message */ method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "DelayEcho"); dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); dbus_connection_send_with_reply (conn, method, &pending, timeout_milliseconds); dbus_message_unref (method); /* block on the message */ dbus_pending_call_block (pending); /* check the reply only to make sure we are not getting errors unrelated to the block in poll bug */ reply = dbus_pending_call_steal_reply (pending); if (reply == NULL) { printf ("Failed: Reply is NULL ***\n"); exit (1); } if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); exit (1); } dbus_message_unref (reply); dbus_pending_call_unref (pending); } static void _run_iteration (DBusConnection *conn) { _method_call (conn, -1); _method_call (conn, 10000); _method_call (conn, INT_MAX); } int main (int argc, char *argv[]) { long start_tv_sec, start_tv_usec; long end_tv_sec, end_tv_usec; int i; DBusMessage *method; DBusConnection *conn; DBusError error; printf ("*** Testing pending call timeouts\n"); dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); /* run 100 times to make sure */ for (i = 0; i < 100; i++) { long delta; _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec); _run_iteration (conn); _dbus_get_monotonic_time (&end_tv_sec, &end_tv_usec); /* we just care about seconds */ delta = end_tv_sec - start_tv_sec; printf ("Iter %i: %lis\n", i, delta); } method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Exit"); dbus_connection_send (conn, method, NULL); dbus_message_unref (method); printf ("Success ***\n"); exit (0); } dbus-1.10.6/test/name-test/test-pending-call-dispatch.c0000644000175000017500000000733012602773110022667 0ustar00smcvsmcv00000000000000/** * Test to make sure we don't get stuck polling a dbus connection * which has no data on the socket. This was an issue where * one pending call would read all the data off the bus * and the second pending call would not check to see * if its data had already been read before polling the connection * and blocking. **/ #include #include #include #include #include static void _run_iteration (DBusConnection *conn) { DBusPendingCall *echo_pending; DBusPendingCall *dbus_pending; DBusMessage *method; DBusMessage *reply; char *echo = "echo"; /* send the first message */ method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Echo"); dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); dbus_connection_send_with_reply (conn, method, &echo_pending, -1); dbus_message_unref (method); /* send the second message */ method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, "org.freedesktop.Introspectable", "Introspect"); dbus_connection_send_with_reply (conn, method, &dbus_pending, -1); dbus_message_unref (method); /* block on the second message (should return immediately) */ dbus_pending_call_block (dbus_pending); /* block on the first message */ /* if it does not return immediately chances are we hit the block in poll bug */ dbus_pending_call_block (echo_pending); /* check the reply only to make sure we are not getting errors unrelated to the block in poll bug */ reply = dbus_pending_call_steal_reply (echo_pending); if (reply == NULL) { printf ("Failed: Reply is NULL ***\n"); exit (1); } if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); exit (1); } dbus_message_unref (reply); dbus_pending_call_unref (dbus_pending); dbus_pending_call_unref (echo_pending); } int main (int argc, char *argv[]) { long start_tv_sec, start_tv_usec; long end_tv_sec, end_tv_usec; int i; DBusMessage *method; DBusConnection *conn; DBusError error; /* Time each iteration and make sure it doesn't take more than 5 seconds to complete. Outside influences may cause connections to take longer but if it does and we are stuck in a poll call then we know the stuck in poll bug has come back to haunt us */ printf ("*** Testing stuck in poll\n"); dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); /* run 100 times to make sure */ for (i = 0; i < 100; i++) { long delta; _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec); _run_iteration (conn); _dbus_get_monotonic_time (&end_tv_sec, &end_tv_usec); /* we just care about seconds */ delta = end_tv_sec - start_tv_sec; printf ("Iter %i: %lis\n", i, delta); if (delta >= 5) { printf ("Failed: looks like we might have been be stuck in poll ***\n"); exit (1); } } method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", "/org/freedesktop/TestSuite", "org.freedesktop.TestSuite", "Exit"); dbus_connection_send (conn, method, NULL); dbus_message_unref (method); printf ("Success ***\n"); exit (0); } dbus-1.10.6/test/name-test/test-ids.c0000644000175000017500000000234512602773110017315 0ustar00smcvsmcv00000000000000#include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif static void die (const char *message) { fprintf (stderr, "*** test-ids: %s", message); exit (1); } int main (int argc, char **argv) { DBusError error; DBusConnection *connection; char *id; char *server_id; dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { fprintf (stderr, "*** Failed to open connection to system bus: %s\n", error.message); dbus_error_free (&error); return 1; } server_id = dbus_connection_get_server_id (connection); if (server_id == NULL) die ("No bus server ID retrieved\n"); /* printf("'%s'\n", server_id); */ if (strlen (server_id) != 32) die ("Bus server id should have length 32\n"); dbus_free (server_id); id = dbus_bus_get_id (connection, NULL); if (id == NULL) die ("No bus ID retrieved\n"); /* printf("'%s'\n", id); */ if (strlen (id) != 32) die ("Bus ID should have length 32\n"); dbus_free (id); _dbus_verbose ("*** Test IDs exiting\n"); return 0; } dbus-1.10.6/test/name-test/test-autolaunch.c0000644000175000017500000000237712602773110020706 0ustar00smcvsmcv00000000000000#include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "dbus/dbus-sysdeps.h" int main (int argc, char *argv[]) { DBusConnection *conn = NULL; DBusError error; dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", NULL); dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); #ifdef DBUS_ENABLE_X11_AUTOLAUNCH /* If X11 autolaunch was enabled, we expect dbus-launch to have worked. */ if (_dbus_getenv ("DISPLAY") != NULL && dbus_error_is_set (&error)) { fprintf (stderr, "*** Failed to autolaunch session bus: %s\n", error.message); dbus_error_free (&error); return 1; } #endif /* We don't necessarily expect it to *work* without X (although it might - * for instance on Mac OS it might have used launchd). Just check that the * results are consistent. */ if (dbus_error_is_set (&error) && conn != NULL) { fprintf (stderr, "*** Autolaunched session bus, but an error was set!\n"); return 1; } if (!dbus_error_is_set (&error) && conn == NULL) { fprintf (stderr, "*** Failed to autolaunch session bus but no error was set\n"); return 1; } return 0; } dbus-1.10.6/test/name-test/Makefile.in0000644000175000017500000012156312627362261017476 0ustar00smcvsmcv00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = $(am__EXEEXT_1) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@am__append_1 = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ run-test.sh \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ run-test-systemserver.sh \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ $(NULL) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@noinst_PROGRAMS = test-pending-call-dispatch$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-pending-call-timeout$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-threads-init$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-ids$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-shutdown$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-privserver$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-privserver-client$(EXEEXT) \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ test-autolaunch$(EXEEXT) subdir = test/name-test ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ $(top_srcdir)/m4/compiler.m4 \ $(top_srcdir)/m4/ld-version-script.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/m4/tp-compiler-flag.m4 \ $(top_srcdir)/m4/tp-compiler-warnings.m4 \ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) test_autolaunch_SOURCES = test-autolaunch.c test_autolaunch_OBJECTS = test-autolaunch.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_autolaunch_DEPENDENCIES = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ ../libdbus-testutils.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = test_ids_SOURCES = test-ids.c test_ids_OBJECTS = test-ids.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_ids_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la test_pending_call_dispatch_SOURCES = test-pending-call-dispatch.c test_pending_call_dispatch_OBJECTS = \ test-pending-call-dispatch.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_pending_call_dispatch_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la test_pending_call_timeout_SOURCES = test-pending-call-timeout.c test_pending_call_timeout_OBJECTS = \ test-pending-call-timeout.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_pending_call_timeout_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la test_privserver_SOURCES = test-privserver.c test_privserver_OBJECTS = test-privserver.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_privserver_DEPENDENCIES = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ ../libdbus-testutils.la test_privserver_client_SOURCES = test-privserver-client.c test_privserver_client_OBJECTS = test-privserver-client.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_privserver_client_DEPENDENCIES = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ ../libdbus-testutils.la test_shutdown_SOURCES = test-shutdown.c test_shutdown_OBJECTS = test-shutdown.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_shutdown_DEPENDENCIES = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ ../libdbus-testutils.la test_threads_init_SOURCES = test-threads-init.c test_threads_init_OBJECTS = test-threads-init.$(OBJEXT) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_threads_init_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = test-autolaunch.c test-ids.c test-pending-call-dispatch.c \ test-pending-call-timeout.c test-privserver.c \ test-privserver-client.c test-shutdown.c test-threads-init.c DIST_SOURCES = test-autolaunch.c test-ids.c \ test-pending-call-dispatch.c test-pending-call-timeout.c \ test-privserver.c test-privserver-client.c test-shutdown.c \ test-threads-init.c am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@am__EXEEXT_1 = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ run-test.sh \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ run-test-systemserver.sh TEST_SUITE_LOG = test-suite.log am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.sh.log=.log) SH_LOG_COMPILE = $(SH_LOG_COMPILER) $(AM_SH_LOG_FLAGS) $(SH_LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ADT_LIBS = @ADT_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPARMOR_CFLAGS = @APPARMOR_CFLAGS@ APPARMOR_LIBS = @APPARMOR_LIBS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FILEVERSION = @BUILD_FILEVERSION@ BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIR_FROM_PKGSYSCONFDIR = @DATADIR_FROM_PKGSYSCONFDIR@ DBUS_BINDIR = @DBUS_BINDIR@ DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ DBUS_DATADIR = @DBUS_DATADIR@ DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ DBUS_PREFIX = @DBUS_PREFIX@ DBUS_SESSION_BUS_CONNECT_ADDRESS = @DBUS_SESSION_BUS_CONNECT_ADDRESS@ DBUS_SESSION_BUS_LISTEN_ADDRESS = @DBUS_SESSION_BUS_LISTEN_ADDRESS@ DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL = @DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL@ DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ DBUS_STATIC_BUILD_CPPFLAGS = @DBUS_STATIC_BUILD_CPPFLAGS@ DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ DBUS_TEST_DATA = @DBUS_TEST_DATA@ DBUS_TEST_EXEC = @DBUS_TEST_EXEC@ DBUS_TEST_USER = @DBUS_TEST_USER@ DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ DBUS_USER = @DBUS_USER@ DBUS_VERSION = @DBUS_VERSION@ DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ DBUS_X_LIBS = @DBUS_X_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUCKTYPE = @DUCKTYPE@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXPANDED_BINDIR = @EXPANDED_BINDIR@ EXPANDED_DATADIR = @EXPANDED_DATADIR@ EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ EXPANDED_PREFIX = @EXPANDED_PREFIX@ EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GREP = @GREP@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LAUNCHCTL = @LAUNCHCTL@ LAUNCHD_AGENT_DIR = @LAUNCHD_AGENT_DIR@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBDBUS_LIBS = @LIBDBUS_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ LT_REVISION = @LT_REVISION@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETWORK_libs = @NETWORK_libs@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RC = @RC@ R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ SED = @SED@ SELINUX_LIBS = @SELINUX_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOVERSION = @SOVERSION@ STRIP = @STRIP@ SYSCONFDIR_FROM_PKGDATADIR = @SYSCONFDIR_FROM_PKGDATADIR@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ SYSTEMD_LIBS = @SYSTEMD_LIBS@ TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ TEST_LISTEN = @TEST_LISTEN@ TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ THREAD_LIBS = @THREAD_LIBS@ VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ VALGRIND_LIBS = @VALGRIND_LIBS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XMKMF = @XMKMF@ XMLTO = @XMLTO@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ XSLTPROC = @XSLTPROC@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ YELP_BUILD = @YELP_BUILD@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ dbus_daemondir = @dbus_daemondir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemduserunitdir = @systemduserunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ -DDBUS_COMPILATION \ $(NULL) # if assertions are enabled, improve backtraces AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ TEST_EXTENSIONS = .sh SH_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh SH_LOG_COMPILER = $(SHELL) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@AM_TESTS_ENVIRONMENT = \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export DBUS_TOP_BUILDDIR=@abs_top_builddir@; \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export DBUS_TOP_SRCDIR=@abs_top_srcdir@; \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export PYTHON=@PYTHON@; \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ $(NULL) EXTRA_DIST = run-test.sh run-test-systemserver.sh test-wait-for-echo.py test-activation-forking.py @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_pending_call_dispatch_LDADD = $(top_builddir)/dbus/libdbus-1.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_pending_call_timeout_LDADD = $(top_builddir)/dbus/libdbus-1.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_threads_init_LDADD = $(top_builddir)/dbus/libdbus-1.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_ids_LDADD = $(top_builddir)/dbus/libdbus-1.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_shutdown_LDADD = ../libdbus-testutils.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_privserver_LDADD = ../libdbus-testutils.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_privserver_client_LDADD = ../libdbus-testutils.la @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@test_autolaunch_LDADD = ../libdbus-testutils.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .log .o .obj .sh .sh$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/name-test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/name-test/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test-autolaunch$(EXEEXT): $(test_autolaunch_OBJECTS) $(test_autolaunch_DEPENDENCIES) $(EXTRA_test_autolaunch_DEPENDENCIES) @rm -f test-autolaunch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_autolaunch_OBJECTS) $(test_autolaunch_LDADD) $(LIBS) test-ids$(EXEEXT): $(test_ids_OBJECTS) $(test_ids_DEPENDENCIES) $(EXTRA_test_ids_DEPENDENCIES) @rm -f test-ids$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ids_OBJECTS) $(test_ids_LDADD) $(LIBS) test-pending-call-dispatch$(EXEEXT): $(test_pending_call_dispatch_OBJECTS) $(test_pending_call_dispatch_DEPENDENCIES) $(EXTRA_test_pending_call_dispatch_DEPENDENCIES) @rm -f test-pending-call-dispatch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_pending_call_dispatch_OBJECTS) $(test_pending_call_dispatch_LDADD) $(LIBS) test-pending-call-timeout$(EXEEXT): $(test_pending_call_timeout_OBJECTS) $(test_pending_call_timeout_DEPENDENCIES) $(EXTRA_test_pending_call_timeout_DEPENDENCIES) @rm -f test-pending-call-timeout$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_pending_call_timeout_OBJECTS) $(test_pending_call_timeout_LDADD) $(LIBS) test-privserver$(EXEEXT): $(test_privserver_OBJECTS) $(test_privserver_DEPENDENCIES) $(EXTRA_test_privserver_DEPENDENCIES) @rm -f test-privserver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_privserver_OBJECTS) $(test_privserver_LDADD) $(LIBS) test-privserver-client$(EXEEXT): $(test_privserver_client_OBJECTS) $(test_privserver_client_DEPENDENCIES) $(EXTRA_test_privserver_client_DEPENDENCIES) @rm -f test-privserver-client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_privserver_client_OBJECTS) $(test_privserver_client_LDADD) $(LIBS) test-shutdown$(EXEEXT): $(test_shutdown_OBJECTS) $(test_shutdown_DEPENDENCIES) $(EXTRA_test_shutdown_DEPENDENCIES) @rm -f test-shutdown$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_shutdown_OBJECTS) $(test_shutdown_LDADD) $(LIBS) test-threads-init$(EXEEXT): $(test_threads_init_OBJECTS) $(test_threads_init_DEPENDENCIES) $(EXTRA_test_threads_init_DEPENDENCIES) @rm -f test-threads-init$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_threads_init_OBJECTS) $(test_threads_init_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-autolaunch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ids.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-pending-call-dispatch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-pending-call-timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-privserver-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-privserver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-shutdown.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-threads-init.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? .sh.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.sh$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dbus-1.10.6/test/name-test/Makefile.am0000644000175000017500000000344712624704607017466 0ustar00smcvsmcv00000000000000AM_CPPFLAGS = \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ -DDBUS_COMPILATION \ $(NULL) # if assertions are enabled, improve backtraces AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ TEST_EXTENSIONS = .sh SH_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh SH_LOG_COMPILER = $(SHELL) ## note that TESTS has special meaning (stuff to use in make check) ## so if adding tests not to be run in make check, don't add them to ## TESTS TESTS = if DBUS_ENABLE_EMBEDDED_TESTS if DBUS_UNIX AM_TESTS_ENVIRONMENT = \ export DBUS_TOP_BUILDDIR=@abs_top_builddir@; \ export DBUS_TOP_SRCDIR=@abs_top_srcdir@; \ export PYTHON=@PYTHON@; \ export DBUS_TEST_DATA=@abs_top_builddir@/test/data; \ export DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT); \ export XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR; \ $(NULL) TESTS += \ run-test.sh \ run-test-systemserver.sh \ $(NULL) endif endif EXTRA_DIST=run-test.sh run-test-systemserver.sh test-wait-for-echo.py test-activation-forking.py if DBUS_ENABLE_EMBEDDED_TESTS ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we ## build even when not doing "make check" noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-threads-init test-ids test-shutdown test-privserver test-privserver-client test-autolaunch test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-1.la test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-1.la test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-1.la test_ids_LDADD=$(top_builddir)/dbus/libdbus-1.la test_shutdown_LDADD=../libdbus-testutils.la test_privserver_LDADD=../libdbus-testutils.la test_privserver_client_LDADD=../libdbus-testutils.la test_autolaunch_LDADD=../libdbus-testutils.la endif dbus-1.10.6/test/name-test/tmp-session-like-system.conf0000644000175000017500000000744012627362361023023 0ustar00smcvsmcv00000000000000 session unix:tmpdir=/tmp 1000000000 1000000000 1000000000 120000 240000 100000 10000 100000 10000 50000 50000 50000 300000 dbus-1.10.6/test/internals/0000755000175000017500000000000012627367774015541 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/internals/syslog.c0000644000175000017500000000566712602773110017215 0ustar00smcvsmcv00000000000000/* Manual regression test for syslog support * * Author: Simon McVittie * Copyright © 2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include "test-utils-glib.h" typedef struct { int dummy; } Fixture; static void setup (Fixture *f, gconstpointer data) { } /* hopefully clear enough that people don't think these messages in syslog * are a bug */ #define MESSAGE "regression test for _dbus_system_log(): " static void test_syslog (Fixture *f, gconstpointer data) { #ifndef G_OS_WIN32 if (g_test_trap_fork (0, 0)) { _dbus_init_system_log (FALSE); _dbus_system_log (DBUS_SYSTEM_LOG_FATAL, MESSAGE "%d", 23); /* should not be reached: exit 0 so the assertion in the main process * will fail */ exit (0); } g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*" MESSAGE "23\n*"); if (g_test_trap_fork (0, 0)) { _dbus_init_system_log (FALSE); _dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42); _dbus_system_log (DBUS_SYSTEM_LOG_WARNING, MESSAGE "%d", 45); _dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666); exit (0); } g_test_trap_assert_passed (); g_test_trap_assert_stderr ("*" MESSAGE "42\n*" MESSAGE "45\n*" MESSAGE "666\n*"); #endif /* manual test (this is the best we can do on Windows) */ _dbus_init_system_log (FALSE); _dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42); _dbus_system_log (DBUS_SYSTEM_LOG_WARNING, MESSAGE "%d", 45); _dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666); } static void teardown (Fixture *f, gconstpointer data) { } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/syslog", Fixture, NULL, setup, test_syslog, teardown); return g_test_run (); } dbus-1.10.6/test/internals/refs.c0000644000175000017500000003574112622707003016630 0ustar00smcvsmcv00000000000000/* Regression test for thread-safe reference-counting * * Author: Simon McVittie * Copyright © 2011 Nokia Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "test-utils-glib.h" static void assert_no_error (const DBusError *e) { if (G_UNLIKELY (dbus_error_is_set (e))) g_error ("expected success but got error: %s: %s", e->name, e->message); } #define N_THREADS 200 #define N_REFS 10000 G_STATIC_ASSERT (((unsigned) N_THREADS * (unsigned) N_REFS) < G_MAXINT32); static dbus_int32_t connection_slot = -1; static dbus_int32_t server_slot = -1; static dbus_int32_t message_slot = -1; static dbus_int32_t pending_call_slot = -1; typedef struct { DBusError e; DBusLoop *loop; DBusServer *server; DBusConnection *connection; DBusConnection *server_connection; DBusMessage *message; GThread *threads[N_THREADS]; gboolean last_unref; unsigned n_refs; unsigned n_threads; } Fixture; typedef void *(*RefFunc) (void *); typedef void (*VoidFunc) (void *); typedef struct { const Fixture *f; void *thing; RefFunc ref; VoidFunc ref_void; VoidFunc unref; void *mutex; VoidFunc lock; VoidFunc unlock; } Thread; /* provide backwards compatibility shim when building with a glib <= 2.30.x */ #if !GLIB_CHECK_VERSION(2,31,0) #define g_thread_new(name,func,data) g_thread_create(func,data,TRUE,NULL) #endif static gpointer ref_thread (gpointer data) { Thread *thread = data; const Fixture *f = thread->f; unsigned i; for (i = 0; i < f->n_refs; i++) { if (thread->lock != NULL) (thread->lock) (thread->mutex); if (thread->ref != NULL) { gpointer ret = (thread->ref) (thread->thing); g_assert (ret == thread->thing); } else { (thread->ref_void) (thread->thing); } if (thread->unlock != NULL) (thread->unlock) (thread->mutex); } return NULL; } static gpointer cycle_thread (gpointer data) { Thread *thread = data; const Fixture *f = thread->f; unsigned i; for (i = 0; i < f->n_refs; i++) { if (thread->lock != NULL) (thread->lock) (thread->mutex); if (thread->ref != NULL) { gpointer ret = (thread->ref) (thread->thing); g_assert (ret == thread->thing); } else { (thread->ref_void) (thread->thing); } (thread->unref) (thread->thing); if (thread->unlock != NULL) (thread->unlock) (thread->mutex); } return NULL; } static gpointer unref_thread (gpointer data) { Thread *thread = data; const Fixture *f = thread->f; unsigned i; for (i = 0; i < f->n_refs; i++) { if (thread->lock != NULL) (thread->lock) (thread->mutex); (thread->unref) (thread->thing); if (thread->unlock != NULL) (thread->unlock) (thread->mutex); } return NULL; } static void last_unref (void *data) { Fixture *f = data; g_assert (!f->last_unref); f->last_unref = TRUE; } static void wait_for_all_threads (Fixture *f) { unsigned i; for (i = 0; i < f->n_threads; i++) g_thread_join (f->threads[i]); } static void new_conn_cb (DBusServer *server, DBusConnection *server_connection, void *data) { Fixture *f = data; g_assert (f->server_connection == NULL); f->server_connection = dbus_connection_ref (server_connection); test_connection_setup (f->loop, f->server_connection); } static void setup (Fixture *f, gconstpointer data) { if (!dbus_threads_init_default ()) g_error ("OOM"); f->n_threads = N_THREADS; f->n_refs = N_REFS; // wine sets WINESERVERSOCKET for its child processes automatically if (g_getenv ("WINESERVERSOCKET") != NULL) { /* Our reference-counting is really slow under Wine (it involves * IPC to wineserver). Do fewer iterations: enough to demonstrate * that it works, rather than a performance test. */ f->n_threads = 10; f->n_refs = 10; } f->loop = _dbus_loop_new (); g_assert (f->loop != NULL); dbus_error_init (&f->e); f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e); assert_no_error (&f->e); g_assert (f->server != NULL); if (!dbus_connection_allocate_data_slot (&connection_slot)) g_error ("OOM"); if (!dbus_server_allocate_data_slot (&server_slot)) g_error ("OOM"); if (!dbus_message_allocate_data_slot (&message_slot)) g_error ("OOM"); if (!dbus_pending_call_allocate_data_slot (&pending_call_slot)) g_error ("OOM"); } static void setup_connection (Fixture *f, gconstpointer data) { char *address; setup (f, data); dbus_server_set_new_connection_function (f->server, new_conn_cb, f, NULL); if (!test_server_setup (f->loop, f->server)) g_error ("failed to set up server"); address = dbus_server_get_address (f->server); g_assert (address != NULL); f->connection = dbus_connection_open_private (address, &f->e); assert_no_error (&f->e); g_assert (f->connection != NULL); dbus_free (address); if (!test_connection_setup (f->loop, f->connection)) g_error ("failed to set up connection"); while (f->server_connection == NULL) _dbus_loop_iterate (f->loop, TRUE); test_connection_shutdown (f->loop, f->connection); test_server_shutdown (f->loop, f->server); } static void test_connection (Fixture *f, gconstpointer data) { Thread public_api = { f, f->connection, (RefFunc) dbus_connection_ref, NULL, (VoidFunc) dbus_connection_unref, NULL, NULL, NULL }; Thread internal_api = { f, f->connection, (RefFunc) _dbus_connection_ref_unlocked, NULL, (VoidFunc) _dbus_connection_unref_unlocked, f->connection, (VoidFunc) _dbus_connection_lock, (VoidFunc) _dbus_connection_unlock }; unsigned i; /* Use a slot as a pseudo-weakref */ if (!dbus_connection_set_data (f->connection, connection_slot, f, last_unref)) g_error ("OOM"); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); else f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); else f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); /* Destroy the connection. This should be the last-unref. */ g_assert (!f->last_unref); dbus_connection_close (f->connection); dbus_connection_unref (f->connection); f->connection = NULL; g_assert (f->last_unref); } static void server_lock (void *server) { SERVER_LOCK (((DBusServer *) server)); } static void server_unlock (void *server) { SERVER_UNLOCK (((DBusServer *) server)); } static void test_server (Fixture *f, gconstpointer data) { Thread public_api = { f, f->server, (RefFunc) dbus_server_ref, NULL, (VoidFunc) dbus_server_unref, NULL, NULL, NULL }; Thread internal_api = { f, f->server, NULL, (VoidFunc) _dbus_server_ref_unlocked, (VoidFunc) _dbus_server_unref_unlocked, f->server, server_lock, server_unlock }; unsigned i; if (!dbus_server_set_data (f->server, server_slot, f, last_unref)) g_error ("OOM"); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); else f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); else f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); /* Destroy the server. This should be the last-unref. */ g_assert (!f->last_unref); dbus_server_disconnect (f->server); dbus_server_unref (f->server); f->server = NULL; g_assert (f->last_unref); } static void test_message (Fixture *f, gconstpointer data) { DBusMessage *message = dbus_message_new_signal ("/foo", "foo.bar.baz", "Foo"); Thread public_api = { f, message, (RefFunc) dbus_message_ref, NULL, (VoidFunc) dbus_message_unref, NULL, NULL, NULL }; unsigned i; if (!dbus_message_set_data (message, message_slot, f, last_unref)) g_error ("OOM"); for (i = 0; i < f->n_threads; i++) { f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); /* Destroy the server. This should be the last-unref. */ g_assert (!f->last_unref); dbus_message_unref (message); g_assert (f->last_unref); } static void test_pending_call (Fixture *f, gconstpointer data) { Thread public_api = { f, NULL, (RefFunc) dbus_pending_call_ref, NULL, (VoidFunc) dbus_pending_call_unref, NULL, NULL, NULL }; Thread internal_api = { f, NULL, (RefFunc) _dbus_pending_call_ref_unlocked, NULL, (VoidFunc) dbus_pending_call_unref, f->connection, (VoidFunc) _dbus_connection_lock, (VoidFunc) _dbus_connection_unlock }; /* This one can't be used to ref, only to cycle or unref. */ Thread unref_and_unlock_api = { f, NULL, (RefFunc) _dbus_pending_call_ref_unlocked, NULL, (VoidFunc) _dbus_pending_call_unref_and_unlock, f->connection, (VoidFunc) _dbus_connection_lock, NULL }; unsigned i; DBusPendingCall *pending_call; _dbus_connection_lock (f->connection); pending_call = _dbus_pending_call_new_unlocked (f->connection, DBUS_TIMEOUT_INFINITE, NULL); g_assert (pending_call != NULL); _dbus_connection_unlock (f->connection); public_api.thing = pending_call; internal_api.thing = pending_call; unref_and_unlock_api.thing = pending_call; if (!dbus_pending_call_set_data (pending_call, pending_call_slot, f, last_unref)) g_error ("OOM"); for (i = 0; i < f->n_threads; i++) { if ((i % 2) == 0) f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { switch (i % 3) { case 0: f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); break; case 1: f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); break; default: f->threads[i] = g_thread_new (NULL, cycle_thread, &unref_and_unlock_api); } g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); for (i = 0; i < f->n_threads; i++) { switch (i % 3) { case 0: f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); break; case 1: f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); break; default: f->threads[i] = g_thread_new (NULL, unref_thread, &unref_and_unlock_api); } g_assert (f->threads[i] != NULL); } wait_for_all_threads (f); /* Destroy the pending call. This should be the last-unref. */ g_assert (!f->last_unref); dbus_pending_call_unref (pending_call); g_assert (f->last_unref); } static void teardown (Fixture *f, gconstpointer data) { if (f->server_connection != NULL) { dbus_connection_close (f->server_connection); dbus_connection_unref (f->server_connection); } if (f->connection != NULL) { dbus_connection_close (f->connection); dbus_connection_unref (f->connection); } if (f->server != NULL) { dbus_server_disconnect (f->server); dbus_server_unref (f->server); } dbus_connection_free_data_slot (&connection_slot); dbus_server_free_data_slot (&server_slot); dbus_message_free_data_slot (&message_slot); dbus_pending_call_free_data_slot (&pending_call_slot); _dbus_loop_unref (f->loop); dbus_error_free (&f->e); } int main (int argc, char **argv) { test_init (&argc, &argv); g_test_add ("/refs/connection", Fixture, NULL, setup_connection, test_connection, teardown); g_test_add ("/refs/message", Fixture, NULL, setup, test_message, teardown); g_test_add ("/refs/pending-call", Fixture, NULL, setup_connection, test_pending_call, teardown); g_test_add ("/refs/server", Fixture, NULL, setup, test_server, teardown); return g_test_run (); } dbus-1.10.6/test/internals/printf.c0000644000175000017500000000576112602773110017172 0ustar00smcvsmcv00000000000000/* Regression test for _dbus_printf_string_upper_bound * * Author: Simon McVittie * Copyright © 2013 Intel Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include "test-utils.h" #include #include static void do_test (int minimum, const char *format, ...) { va_list ap; int result; va_start (ap, format); result = _dbus_printf_string_upper_bound (format, ap); va_end (ap); if (result < minimum) { fprintf (stderr, "expected at least %d, got %d\n", minimum, result); abort (); } } #define X_TIMES_8 "XXXXXXXX" #define X_TIMES_16 X_TIMES_8 X_TIMES_8 #define X_TIMES_32 X_TIMES_16 X_TIMES_16 #define X_TIMES_64 X_TIMES_32 X_TIMES_32 #define X_TIMES_128 X_TIMES_64 X_TIMES_64 #define X_TIMES_256 X_TIMES_128 X_TIMES_128 #define X_TIMES_512 X_TIMES_256 X_TIMES_256 #define X_TIMES_1024 X_TIMES_512 X_TIMES_512 /* This test outputs TAP syntax: http://testanything.org/ */ int main (int argc, char **argv) { char buf[] = X_TIMES_1024 X_TIMES_1024 X_TIMES_1024 X_TIMES_1024; int i; int test_num = 0; do_test (1, "%d", 0); printf ("ok %d\n", ++test_num); do_test (7, "%d", 1234567); printf ("ok %d\n", ++test_num); do_test (3, "%f", 3.5); printf ("ok %d\n", ++test_num); do_test (0, "%s", ""); printf ("ok %d\n", ++test_num); do_test (1024, "%s", X_TIMES_1024); printf ("ok %d\n", ++test_num); do_test (1025, "%s", X_TIMES_1024 "Y"); printf ("ok %d\n", ++test_num); for (i = 4096; i > 0; i--) { buf[i] = '\0'; do_test (i, "%s", buf); do_test (i + 3, "%s:%d", buf, 42); } printf ("ok %d\n", ++test_num); /* Tell the TAP driver that we have done all the tests we plan to do. * This is how it can distinguish between an unexpected exit and * successful completion. */ printf ("1..%d\n", test_num); return 0; } dbus-1.10.6/test/data/0000755000175000017500000000000012627367774014453 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files-system/0000755000175000017500000000000012627367774021632 5ustar00smcvsmcv00000000000000org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in0000644000175000017500000000027612602773110036047 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files-system[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ -test "that" 'we get' back --what "we put in" User=anyrandomuser org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in0000644000175000017500000000030212602773110035300 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files-system[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ "this should 'fail' because of an unterminated quote User=anyrandomuser org.freedesktop.DBus.TestSuiteSegfaultService.service.in0000644000175000017500000000020312602773110034410 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files-system[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteSegfaultService Exec=@DBUS_TEST_EXEC@/test-segfault@EXEEXT@ User=anyrandomuser org.freedesktop.DBus.TestSuiteEchoService.service.in0000644000175000017500000000017612602773110033525 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files-system[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteEchoService Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ User=anyrandomuser dbus-1.10.6/test/data/valid-service-files/0000755000175000017500000000000012627367774020310 5ustar00smcvsmcv00000000000000org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in0000644000175000017500000000025312602773110034520 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ -test "that" 'we get' back --what "we put in" org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in0000644000175000017500000000025612602773110033766 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ "this should 'fail' because of an unterminated quote dbus-1.10.6/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in0000644000175000017500000000016012602773110033147 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteSegfaultService Exec=@DBUS_TEST_EXEC@/test-segfault@EXEEXT@ org.freedesktop.DBus.TestSuiteForkingEchoService.service.in0000644000175000017500000000024712602773110033522 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-service-files[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteForkingEchoService Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ org.freedesktop.DBus.TestSuiteForkingEchoService fork dbus-1.10.6/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in0000644000175000017500000000015212602773110032254 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteEchoService Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ dbus-1.10.6/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in0000644000175000017500000000017012602773110032242 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.DBus.TestSuite.PrivServer Exec=@DBUS_TEST_EXEC@/name-test/test-privserver@EXEEXT@ dbus-1.10.6/test/data/valid-messages/0000755000175000017500000000000012627367774017357 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-messages/unknown-header-field.message0000644000175000017500000000053012627362361024714 0ustar00smcvsmcv00000000000000## message with a 'name' header field and unknown 'unkn' field ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS HEADER_FIELD UNKNOWN TYPE DICT LENGTH Dict START_LENGTH Dict STRING 'int32' TYPE INT32 INT32 0x12345678 END_LENGTH Dict ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/standard-service-exists.message0000644000175000017500000000075512627362361025472 0ustar00smcvsmcv00000000000000# Standard org.freedesktop.DBus.ServiceExists message VALID_HEADER method_call HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD MEMBER TYPE STRING STRING 'ServiceExists' HEADER_FIELD DESTINATION TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD SIGNATURE TYPE STRING STRING 's' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE STRING STRING 'org.freedesktop.DBus.Sample' END_LENGTH Body dbus-1.10.6/test/data/valid-messages/standard-list-services.message0000644000175000017500000000067112627362361025306 0ustar00smcvsmcv00000000000000# Standard org.freedesktop.DBus.ListServices message VALID_HEADER method_call HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD MEMBER TYPE STRING STRING 'ListServices' HEADER_FIELD DESTINATION TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD SIGNATURE TYPE STRING STRING '' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/standard-hello.message0000644000175000017500000000065312627362361023615 0ustar00smcvsmcv00000000000000# Standard org.freedesktop.DBus.Hello message VALID_HEADER method_call HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD MEMBER TYPE STRING STRING 'Hello' HEADER_FIELD DESTINATION TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD SIGNATURE TYPE STRING STRING '' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/standard-acquire-service.message0000644000175000017500000000100512627362361025571 0ustar00smcvsmcv00000000000000# Standard org.freedesktop.DBus.AcquireService message VALID_HEADER method_call HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD MEMBER TYPE STRING STRING 'AcquireService' HEADER_FIELD DESTINATION TYPE STRING STRING 'org.freedesktop.DBus' HEADER_FIELD SIGNATURE TYPE STRING STRING 'su' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE STRING STRING 'org.freedesktop.DBus.Sample' TYPE UINT32 UINT32 0 END_LENGTH Body dbus-1.10.6/test/data/valid-messages/simplest.message0000644000175000017500000000030312627362361022544 0ustar00smcvsmcv00000000000000## simplest possible valid message ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/simplest-manual.message0000644000175000017500000000074012627362361024024 0ustar00smcvsmcv00000000000000## like simplest.message, but doesn't use VALID_HEADER ## convenience command. mostly to test the test framework. LITTLE_ENDIAN BYTE 'l' BYTE 1 BYTE 0 BYTE 0 LENGTH Header LENGTH Body ## client serial INT32 7 HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD SIGNATURE TYPE STRING STRING '' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/recursive-types.message0000644000175000017500000000274312627362361024067 0ustar00smcvsmcv00000000000000## Message with recursive types ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body # Everything is inside a dict TYPE DICT LENGTH Dict1 START_LENGTH Dict1 # first dict entry is an array of array of uint32 STRING 'mega-uint-array' TYPE ARRAY TYPE ARRAY TYPE ARRAY TYPE UINT32 LENGTH Array1 START_LENGTH Array1 LENGTH Array1_1 START_LENGTH Array1_1 UINT32_ARRAY { 1, 2, 3, 4, 5} UINT32_ARRAY { 2, 3, 4, 5, 1} UINT32_ARRAY { 3, 4, 5, 1, 2} END_LENGTH Array1_1 LENGTH Array1_2 START_LENGTH Array1_2 UINT32_ARRAY { 4, 5, 6, 7, 8} UINT32_ARRAY { 5, 6, 7, 8, 4} END_LENGTH Array1_2 END_LENGTH Array1 # second dict entry is an array of strings STRING 'string-array' TYPE ARRAY TYPE STRING STRING_ARRAY { 'a', 'string', 'array'} # third dict entry is another dict STRING 'nested-dict' TYPE DICT LENGTH Dict2 START_LENGTH Dict2 STRING 'string' TYPE STRING STRING 'a deeply nested string' STRING 'super-nested-dict' TYPE DICT LENGTH Dict3 START_LENGTH Dict3 STRING 'double-array' TYPE ARRAY TYPE DOUBLE DOUBLE_ARRAY {1.0, 2.0, 3.0} STRING 'dict-array' TYPE ARRAY TYPE DICT LENGTH Array2 START_LENGTH Array2 LENGTH Dict4 START_LENGTH Dict4 STRING 'key4' TYPE BYTE BYTE '4' END_LENGTH Dict4 LENGTH Dict5 START_LENGTH Dict5 STRING 'key5' TYPE BYTE BYTE '5' END_LENGTH Dict5 END_LENGTH Array2 STRING 'boolean' TYPE BOOLEAN BOOLEAN false END_LENGTH Dict3 END_LENGTH Dict2 END_LENGTH Dict1 END_LENGTH Body dbus-1.10.6/test/data/valid-messages/opposite-endian.message0000644000175000017500000000065712627362361024016 0ustar00smcvsmcv00000000000000## Message of opposite endianness, with lots of random fields in it OPPOSITE_ENDIAN ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS HEADER_FIELD UNKNOWN TYPE INT32 INT32 0xfeeb ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE INT32 INT32 89765432 TYPE UINT32 UINT32 0xfffffff TYPE STRING STRING 'Hello this is a string' TYPE DOUBLE DOUBLE 3.14159 TYPE NIL END_LENGTH Body dbus-1.10.6/test/data/valid-messages/no-padding.message0000644000175000017500000000063012627362361022727 0ustar00smcvsmcv00000000000000## Message with no header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS ## this byte array is filled with zeros to the natural length ## of the header HEADER_FIELD UNKNOWN TYPE ARRAY TYPE BYTE ALIGN 4 LENGTH ThisByteArray START_LENGTH ThisByteArray BYTE 1 ALIGN 8 1 END_LENGTH ThisByteArray END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/valid-messages/lots-of-arguments.message0000644000175000017500000000216012627362361024275 0ustar00smcvsmcv00000000000000# Message with lots of different argument types VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE NIL TYPE BYTE BYTE 42 TYPE INT32 INT32 0x12345678 TYPE UINT32 UINT32 0x8765432 TYPE DOUBLE DOUBLE 3.141592653589 TYPE STRING STRING 'This is a string' TYPE ARRAY TYPE BOOLEAN BOOLEAN_ARRAY { true, false, false, true, false } TYPE ARRAY TYPE INT32 INT32_ARRAY { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10 } TYPE ARRAY TYPE UINT32 UINT32_ARRAY { 11, 12, 314, 1911, 57692, 1237, 2834 } TYPE ARRAY TYPE DOUBLE DOUBLE_ARRAY { 0.1, 0.2, 3.1415926, 2.7183, 10.0, 9.99 } TYPE ARRAY TYPE STRING STRING_ARRAY { 'Hello', 'This', 'Is', 'A', 'String', 'Array!' } TYPE CUSTOM STRING 'named type' BYTE_ARRAY { 'b', 'i', 'n', 'a', 'r', 'y', 'd', 'a', 't', 'a' } TYPE ARRAY TYPE DICT LENGTH Array START_LENGTH Array LENGTH Dict1 START_LENGTH Dict1 STRING 'key1' TYPE INT32 INT32 0x12345678 STRING 'key2' TYPE UINT32 UINT32 0x8765432 END_LENGTH Dict1 LENGTH Dict2 START_LENGTH Dict2 STRING 'key1' TYPE INT32 INT32 0x12345678 STRING 'key2' TYPE UINT32 UINT32 0x8765432 END_LENGTH Dict2 END_LENGTH Array END_LENGTH Body dbus-1.10.6/test/data/valid-messages/emptiness.message0000644000175000017500000000143612627362361022723 0ustar00smcvsmcv00000000000000# Empty arrays and strings VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE STRING INT32 0 BYTE 0 # Strings need to be NULL-terminated TYPE ARRAY TYPE BOOLEAN INT32 0 TYPE ARRAY TYPE INT32 INT32 0 TYPE ARRAY TYPE UINT32 INT32 0 TYPE ARRAY TYPE DOUBLE INT32 0 TYPE ARRAY TYPE BYTE INT32 0 TYPE ARRAY TYPE STRING INT32 0 TYPE DICT INT32 0 # A dict with empty arrays TYPE DICT LENGTH Dict START_LENGTH Dict STRING 'boolean_array' TYPE ARRAY TYPE BOOLEAN INT32 0 STRING 'int32_array' TYPE ARRAY TYPE INT32 INT32 0 STRING 'uint32_array' TYPE ARRAY TYPE UINT32 INT32 0 STRING 'double_array' TYPE ARRAY TYPE DOUBLE INT32 0 STRING 'byte_array' TYPE ARRAY TYPE BYTE INT32 0 STRING 'string_array' } TYPE ARRAY TYPE STRING INT32 0 END_LENGTH Dict END_LENGTH Body dbus-1.10.6/test/data/valid-messages/dict.message0000644000175000017500000000162512627362361021637 0ustar00smcvsmcv00000000000000# Dict with different values VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE DICT LENGTH Dict START_LENGTH Dict STRING 'boolean' TYPE BOOLEAN BYTE 1 STRING 'int32' TYPE INT32 INT32 0x12345678 STRING 'uint32' TYPE UINT32 UINT32 0x8765432 STRING 'double' TYPE DOUBLE DOUBLE 3.141592653589 STRING 'string' TYPE STRING STRING 'This is a string' STRING 'boolean_array' TYPE ARRAY TYPE BOOLEAN BOOLEAN_ARRAY { true, false, false, true, false } STRING 'int32_array' TYPE ARRAY TYPE INT32 INT32_ARRAY { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10 } STRING 'uint32_array' TYPE ARRAY TYPE UINT32 UINT32_ARRAY { 11, 12, 314, 1911, 57692, 1237, 2834 } STRING 'double_array' TYPE ARRAY TYPE DOUBLE DOUBLE_ARRAY { 0.1, 0.2, 3.1415926, 2.7183, 10.0, 9.99 } STRING 'string_array' TYPE ARRAY TYPE STRING STRING_ARRAY { 'Hello', 'This', 'Is', 'A', 'String', 'Array!' } END_LENGTH Dict END_LENGTH Body dbus-1.10.6/test/data/valid-messages/dict-simple.message0000644000175000017500000000033112627362361023117 0ustar00smcvsmcv00000000000000# A simple dict VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE DICT LENGTH Dict START_LENGTH Dict STRING 'int32' TYPE INT32 INT32 0x12345678 END_LENGTH Dict END_LENGTH Body dbus-1.10.6/test/data/valid-messages/array-of-array-of-uint32.message0000644000175000017500000000066712627362361025301 0ustar00smcvsmcv00000000000000# Message with an array of array of uint32 VALID_HEADER method_call REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE ARRAY TYPE ARRAY TYPE UINT32 LENGTH Array START_LENGTH Array ## array of uint32 LENGTH SubArray1 START_LENGTH SubArray1 UINT32 1 UINT32 2 UINT32 3 END_LENGTH SubArray1 ## array of uint32 LENGTH SubArray2 START_LENGTH SubArray2 UINT32 4 UINT32 5 END_LENGTH SubArray2 END_LENGTH Array END_LENGTH Body dbus-1.10.6/test/data/valid-config-files-system/0000755000175000017500000000000012627367774021437 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-config-files-system/debug-allow-all-pass.conf.in0000644000175000017500000000117212602773110026602 0ustar00smcvsmcv00000000000000 debug-pipe:name=test-server @TEST_LISTEN@ system @TEST_LAUNCH_HELPER_BINARY@ @DBUS_TEST_DATA@/valid-service-files-system dbus-1.10.6/test/data/valid-config-files-system/debug-allow-all-fail.conf.in0000644000175000017500000000117412602773110026551 0ustar00smcvsmcv00000000000000 debug-pipe:name=test-server @TEST_LISTEN@ system @TEST_LAUNCH_HELPER_BINARY@ @DBUS_TEST_DATA@/invalid-service-files-system dbus-1.10.6/test/data/valid-config-files-system/system.d/0000755000175000017500000000000012627367774023205 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-config-files-system/system.d/test.conf0000644000175000017500000000154712627362361025025 0ustar00smcvsmcv00000000000000 dbus-1.10.6/test/data/valid-config-files/0000755000175000017500000000000012627367774020115 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-config-files/many-rules.conf0000644000175000017500000000521112627362361023042 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf 5000 5000 300 5000 6000 50 80 64 64 256 512 dbus-1.10.6/test/data/valid-config-files/listen-unix-runtime.conf0000644000175000017500000000056412627362361024714 0ustar00smcvsmcv00000000000000 session unix:runtime=yes dbus-1.10.6/test/data/valid-config-files/entities.conf0000644000175000017500000000104312627362361022571 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/<bar> tcp:port=1234 basic.d /usr/&share/foo nonexistent.confn dbus-1.10.6/test/data/valid-config-files/basic.conf0000644000175000017500000000223712627362361022034 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf 5000 5000 300 5000 6000 50 80 64 64 256 dbus-1.10.6/test/data/valid-config-files/systemd-activation.conf.in0000644000175000017500000000061212602773110025171 0ustar00smcvsmcv00000000000000 @TEST_LISTEN@ @DBUS_TEST_DATA@/systemd-activation dbus-1.10.6/test/data/valid-config-files/multi-user.conf.in0000644000175000017500000000073712602773110023460 0ustar00smcvsmcv00000000000000 @TEST_LISTEN@ /bin/false dbus-1.10.6/test/data/valid-config-files/incoming-limit.conf.in0000644000175000017500000000112612602773110024262 0ustar00smcvsmcv00000000000000 session @TEST_LISTEN@ 1 dbus-1.10.6/test/data/valid-config-files/forbidding.conf.in0000644000175000017500000000113212602773110023447 0ustar00smcvsmcv00000000000000 session @TEST_LISTEN@ dbus-1.10.6/test/data/valid-config-files/finite-timeout.conf.in0000644000175000017500000000121112602773110024300 0ustar00smcvsmcv00000000000000 session @TEST_LISTEN@ 100 dbus-1.10.6/test/data/valid-config-files/debug-allow-all.conf.in0000644000175000017500000000104012602773110024306 0ustar00smcvsmcv00000000000000 debug-pipe:name=test-server @TEST_LISTEN@ @DBUS_TEST_DATA@/valid-service-files dbus-1.10.6/test/data/valid-config-files/debug-allow-all-sha1.conf.in0000644000175000017500000000110612602773110025143 0ustar00smcvsmcv00000000000000 debug-pipe:name=test-server @TEST_LISTEN@ @DBUS_TEST_DATA@/valid-service-files DBUS_COOKIE_SHA1 dbus-1.10.6/test/data/valid-config-files/basic.d/0000755000175000017500000000000012627367774021420 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/valid-config-files/basic.d/basic.conf0000644000175000017500000000072112627362361023333 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf dbus-1.10.6/test/data/systemd-activation/0000755000175000017500000000000012627367774020302 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/systemd-activation/org.freedesktop.systemd1.service0000644000175000017500000000007612627362361026523 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.systemd1 Exec=/bin/false dbus-1.10.6/test/data/systemd-activation/com.example.SystemdActivatable3.service0000644000175000017500000000020312627362361027724 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=com.example.SystemdActivatable3 Exec=/bin/false 3 SystemdService=dbus-com.example.SystemdActivatable3.service dbus-1.10.6/test/data/systemd-activation/com.example.SystemdActivatable2.service0000644000175000017500000000020312627362361027723 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=com.example.SystemdActivatable2 Exec=/bin/false 2 SystemdService=dbus-com.example.SystemdActivatable2.service dbus-1.10.6/test/data/systemd-activation/com.example.SystemdActivatable1.service0000644000175000017500000000020312627362361027722 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=com.example.SystemdActivatable1 Exec=/bin/false 1 SystemdService=dbus-com.example.SystemdActivatable1.service dbus-1.10.6/test/data/sha-1/0000755000175000017500000000000012627367774015364 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/sha-1/byte-messages.sha10000644000175000017500000052225112627362361020704 0ustar00smcvsmcv00000000000000# Configuration information for "SHA-1 Test" # SHA tests are configured for BYTE oriented implementations H>SHS Type 1 Strings 0 1 ^ 5 0 2 1 2 1 2 ^ 5 0 1 3 4 4 4 ^ 7 0 4 3 4 4 1 4 4 ^ 10 0 4 1 5 3 4 4 3 1 3 4 ^ 10 0 3 1 6 5 5 1 3 6 6 4 ^ 13 1 3 2 5 3 3 3 4 6 6 1 4 6 2 ^ 16 1 3 5 5 1 2 1 3 3 6 3 5 2 3 5 7 2 ^ 15 1 8 1 5 3 2 7 4 5 6 7 3 3 1 6 3 ^ 15 1 4 6 8 2 1 4 2 5 1 6 8 8 6 4 7 ^ 18 1 1 2 7 3 8 6 7 5 4 3 4 3 5 3 3 2 6 8 ^ 16 0 9 8 1 8 1 7 6 7 7 1 2 6 9 5 4 7 ^ 18 0 7 1 7 3 9 4 7 7 5 2 8 1 7 8 2 7 2 9 ^ 19 1 2 3 1 8 8 6 9 10 3 10 8 9 2 4 1 5 1 5 9 ^ 19 1 8 5 4 8 1 3 9 5 7 7 2 7 2 7 8 7 4 8 10 ^ 20 1 1 9 7 4 1 4 5 1 10 8 6 4 4 9 9 9 8 2 9 10 ^ 19 1 11 6 7 7 2 6 2 6 10 6 9 10 5 11 1 6 8 11 4 ^ 22 0 10 5 10 3 7 8 9 9 1 1 1 10 2 1 5 10 2 9 9 9 7 8 ^ 21 0 1 10 1 6 9 4 2 5 2 11 8 12 12 9 8 1 3 10 7 11 12 ^ 24 1 3 9 5 12 3 4 2 9 12 11 6 6 1 1 9 5 9 1 4 9 4 10 8 9 ^ 25 1 3 2 3 11 1 12 5 6 2 7 8 4 8 8 9 9 8 4 9 1 4 8 10 9 9 ^ 23 0 11 10 7 10 10 6 10 9 4 5 10 5 8 4 1 10 12 4 6 1 8 11 6 ^ 22 0 12 8 10 4 3 8 5 5 7 11 13 11 12 11 4 12 3 6 5 11 10 5 ^ 26 1 10 9 6 9 7 2 10 4 4 5 5 2 12 13 5 3 1 10 1 4 7 8 13 13 12 9 ^ 31 0 2 6 5 4 7 3 10 6 13 6 3 9 6 2 10 5 3 8 4 1 11 3 5 3 7 11 1 12 9 12 5 ^ 27 1 14 5 1 3 7 2 3 9 3 4 14 4 4 10 8 5 14 1 11 12 12 10 4 13 7 11 9 ^ 30 1 4 9 5 5 8 9 5 10 4 2 4 7 9 9 6 3 5 1 8 3 2 13 3 14 9 8 9 10 14 10 ^ 27 0 12 9 5 8 7 2 14 12 3 8 14 6 6 4 7 5 7 10 7 11 10 1 9 6 7 12 14 ^ 24 0 12 9 9 2 11 13 12 11 11 6 14 13 10 5 6 8 10 4 3 11 11 14 5 14 ^ 24 0 15 4 5 3 8 12 15 8 14 15 9 12 12 3 10 13 6 11 10 4 13 14 8 8 ^ 28 1 1 8 1 5 11 4 9 12 4 13 15 5 9 11 7 14 11 1 11 7 8 8 11 1 13 15 12 13 ^ 32 1 5 8 3 8 10 7 8 1 5 13 12 14 5 3 6 4 12 15 6 6 10 11 13 9 1 11 6 10 3 7 14 2 ^ 31 0 10 3 5 1 14 11 11 16 1 2 2 11 6 13 15 12 6 5 16 2 14 2 10 12 2 5 5 6 10 13 15 ^ 34 0 3 10 8 16 9 5 12 15 4 11 13 3 6 5 10 8 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 14 ^ 30 1 1 12 4 4 2 15 13 15 11 15 5 11 9 7 15 16 6 16 12 3 2 10 16 5 5 7 1 7 11 16 ^ 34 0 7 9 11 2 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 3 3 6 7 16 7 6 15 5 8 15 14 ^ 36 1 4 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 8 16 2 12 16 10 14 3 2 3 7 14 3 ^ 32 0 15 10 9 1 14 10 14 6 6 16 3 2 3 8 3 12 8 11 17 3 9 7 16 14 4 11 15 5 13 9 5 17 ^ 30 0 17 17 13 8 2 6 8 16 1 12 5 17 2 9 8 10 13 14 11 17 12 5 14 9 11 9 11 4 11 12 ^ 30 1 16 6 10 5 8 3 17 16 14 1 15 15 15 6 13 2 11 6 13 11 13 4 6 7 11 11 12 16 13 16 ^ 33 1 16 16 14 16 2 4 16 11 6 15 7 4 17 6 5 7 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 16 ^ 39 1 2 16 13 7 8 6 2 15 1 9 12 4 4 11 13 7 2 11 9 18 4 5 4 8 2 14 9 9 1 8 13 11 15 8 5 9 10 16 7 ^ 34 0 2 7 1 1 17 13 6 11 10 8 5 12 15 6 15 10 12 4 18 1 2 8 11 12 16 10 12 18 11 16 12 11 17 6 ^ 34 1 4 7 13 7 10 7 10 6 1 12 7 18 11 18 2 10 15 10 14 8 18 9 9 12 12 3 13 12 6 4 9 17 13 17 ^ 40 0 5 7 3 2 1 17 14 4 16 6 13 1 13 6 6 10 1 3 18 3 11 7 9 5 7 11 17 1 9 16 5 15 10 17 3 8 15 17 8 12 ^ 40 0 11 3 15 17 11 1 1 4 3 14 18 4 2 18 8 15 6 4 6 3 15 11 16 10 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 17 ^ 37 1 2 19 12 8 16 14 2 9 16 2 6 6 7 9 10 9 11 9 14 11 15 5 16 9 2 17 2 8 15 8 4 3 14 14 16 16 12 ^ 37 1 11 10 16 12 11 7 14 14 14 6 10 10 1 6 13 19 5 6 4 7 12 12 10 5 10 15 15 8 5 13 17 13 5 6 14 1 19 ^ 38 1 2 6 5 17 9 11 18 18 8 6 13 15 3 3 15 5 13 18 3 2 5 5 14 7 13 4 17 7 2 17 3 18 15 7 15 16 18 11 ^ 38 1 12 8 6 3 17 12 13 19 15 9 7 17 16 15 3 11 11 5 2 13 19 16 2 4 16 7 8 1 2 9 17 12 3 5 18 19 11 9 ^ 39 1 14 16 14 8 9 16 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 3 4 3 7 1 14 19 19 19 ^ 37 1 18 13 11 5 18 4 19 10 6 19 11 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 3 8 10 1 18 1 6 20 14 ^ 36 0 8 9 6 12 11 7 7 3 17 13 6 20 17 9 20 16 10 12 17 8 11 8 11 10 5 10 14 18 8 19 9 12 12 2 20 19 ^ 39 0 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 14 3 6 16 13 10 13 5 16 10 2 8 2 17 19 4 17 7 19 6 9 15 15 6 ^ 43 0 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 8 18 15 5 3 5 12 15 16 10 17 7 19 16 2 1 16 6 3 19 12 5 18 16 ^ 49 1 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 8 17 4 14 4 15 3 2 2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 19 10 2 3 1 10 20 ^ 36 0 19 20 12 5 19 21 5 21 11 14 19 1 17 8 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 6 21 7 11 12 ^ 41 0 12 9 11 6 16 18 18 10 11 20 6 12 11 5 7 21 19 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 13 9 7 10 17 14 ^ 45 0 10 6 8 3 17 18 3 21 19 6 17 15 4 9 15 9 15 14 4 7 14 8 10 13 4 11 10 7 6 21 1 14 5 11 7 7 2 13 13 3 9 13 8 14 20 ^ 39 1 3 7 18 4 9 9 5 15 13 17 10 15 16 20 8 19 9 10 9 1 19 14 21 2 18 13 10 4 18 16 4 21 15 10 18 19 3 12 18 ^ 41 0 14 4 13 11 1 11 1 10 2 12 4 21 10 21 18 9 2 16 7 20 6 7 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 19 ^ 37 0 11 18 1 17 14 15 20 16 20 8 2 17 10 4 21 5 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 21 ^ 48 0 9 22 19 12 8 16 5 17 5 9 1 2 9 6 12 6 1 7 4 3 15 1 14 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 18 ^ 50 1 12 8 20 13 2 9 20 9 14 10 1 16 2 22 6 4 16 14 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 10 ^ 44 0 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 14 10 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 ^ 47 0 15 8 15 3 5 6 2 19 12 17 4 20 8 11 20 2 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 10 18 8 ^ 48 1 5 13 3 21 5 3 6 18 18 10 1 21 21 7 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 15 11 9 13 17 12 ^ 45 0 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 2 4 15 17 21 ^ 45 1 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 4 8 4 20 22 11 ^ 38 0 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 23 18 10 12 8 21 11 6 12 7 19 14 18 17 ^ 40 0 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 22 14 21 9 21 19 14 14 4 18 13 12 14 ^ 48 1 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 22 19 13 8 5 19 7 5 23 1 4 19 11 23 11 21 14 1 3 21 ^ 43 0 22 14 11 7 18 16 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 7 16 13 23 4 13 3 7 22 ^ 47 1 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 18 17 18 7 19 ^ 47 1 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 10 ^ 52 0 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 9 2 24 5 20 13 13 ^ 42 0 20 17 19 22 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 4 24 7 21 18 2 21 16 1 19 18 20 11 3 15 17 ^ 50 0 18 1 6 14 5 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 1 10 2 18 1 21 19 5 18 12 2 22 16 23 15 19 6 18 9 1 23 5 ^ 51 0 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 21 4 19 5 5 20 24 16 ^ 53 1 20 25 17 11 8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 25 ^ 49 1 9 9 14 2 13 17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 25 ^ 47 0 9 18 20 22 21 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 23 ^ 48 1 7 19 1 18 1 14 22 13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 ^ 51 1 19 17 16 22 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 4 ^ 52 1 6 1 11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 11 18 ^ 44 0 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 24 9 24 15 1 23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 4 4 23 21 13 19 15 21 12 ^ 59 1 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 7 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 6 25 3 12 19 6 2 4 24 17 ^ 60 0 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 14 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 1 1 10 11 11 4 12 11 20 3 14 2 3 2 23 15 ^ 49 0 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 24 18 6 12 19 25 7 6 5 2 25 ^ 54 1 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 1 20 25 6 19 8 3 22 16 16 20 ^ 63 0 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 22 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 24 ^ 49 0 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 21 16 24 4 16 3 6 26 26 10 20 13 1 20 24 15 ^ 56 0 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 17 24 20 20 ^ 58 1 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 16 21 17 19 23 ^ 58 1 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 5 26 26 4 9 2 7 25 17 ^ 54 1 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 16 17 1 3 12 1 4 13 3 9 21 26 ^ 56 1 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 22 3 7 6 4 26 3 15 8 25 21 ^ 50 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 27 25 6 1 15 4 7 27 15 ^ 51 0 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 17 7 25 6 23 24 14 25 12 5 13 26 2 5 8 10 16 17 ^ 58 1 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 2 9 25 18 17 8 2 14 4 19 1 5 27 13 24 ^ 53 0 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 9 23 20 3 28 27 12 17 22 ^ 59 0 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 8 3 17 28 18 10 2 5 3 21 21 15 ^ 58 0 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 5 24 23 18 5 14 18 8 4 28 ^ 61 0 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 3 7 5 8 9 26 10 12 25 11 22 ^ 53 0 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 25 7 26 1 13 5 9 20 ^ 58 0 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 12 21 18 25 28 ^ 60 1 29 20 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 24 ^ 64 0 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 15 ^ 56 1 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 22 ^ 51 1 29 28 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 29 ^ 64 1 12 14 12 18 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 9 ^ 60 1 20 8 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 17 ^ 60 0 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 5 9 21 11 ^ 54 0 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 12 ^ 61 1 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 19 ^ 56 1 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 28 ^ 59 1 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 12 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 12 ^ 56 0 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 3 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 29 ^ 63 1 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 14 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 14 ^ 52 0 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 24 ^ 66 1 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 29 ^ 53 1 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 30 ^ 67 0 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 23 ^ 65 0 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 23 ^ 59 1 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 30 ^ 55 1 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 31 ^ 62 0 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 14 ^ 60 0 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 27 ^ 60 1 24 22 4 29 22 31 28 20 4 16 21 3 1 15 5 15 6 30 3 29 29 7 27 20 2 20 31 22 26 9 29 16 4 26 32 17 20 14 28 17 19 6 24 11 26 28 5 18 15 8 16 20 21 4 9 12 4 8 17 29 ^ SHS Type 2 Strings 69 1 5 3 11 15 12 24 31 23 1 6 28 2 8 31 6 7 30 5 19 23 12 6 9 31 19 17 24 25 22 6 12 16 3 7 9 9 11 29 4 11 2 5 13 29 10 12 30 32 18 28 18 27 3 30 4 4 26 6 13 31 13 2 11 7 24 4 17 29 12 ^ 95 0 21 19 21 23 11 42 36 2 13 4 1 33 22 16 27 9 4 33 16 3 30 15 11 32 13 17 38 32 9 38 4 36 15 32 27 19 42 18 6 36 22 10 29 12 25 40 15 29 23 28 30 4 8 11 24 9 10 31 28 43 23 16 29 33 5 40 26 3 19 12 36 43 5 35 37 5 14 11 45 35 16 10 8 32 4 15 35 26 2 39 22 37 22 30 29 ^ 106 1 18 14 51 2 6 32 51 9 32 50 44 46 51 8 11 53 45 55 16 10 3 52 8 20 20 46 46 13 32 2 46 50 43 25 54 9 31 29 2 47 15 29 24 45 44 18 37 14 28 39 36 44 47 16 50 10 44 24 53 35 22 40 20 15 51 22 18 22 42 6 54 49 38 21 7 13 30 16 7 52 16 22 13 38 7 11 44 33 9 25 13 37 42 14 45 53 30 38 5 25 5 35 38 22 28 53 ^ 127 0 58 35 43 28 5 28 63 8 12 25 9 47 53 29 62 7 37 2 3 48 5 12 55 56 28 35 12 63 6 58 27 27 48 44 35 14 17 22 56 10 8 1 16 15 42 63 14 51 57 19 41 7 8 56 47 34 52 22 48 60 43 9 1 52 4 21 49 61 18 50 23 13 46 62 23 45 62 9 56 18 23 31 8 30 27 36 13 38 4 58 53 47 24 18 41 58 19 12 18 52 42 29 44 45 26 63 34 32 41 64 15 26 55 19 2 49 6 30 53 13 54 12 53 37 12 37 43 ^ 148 0 60 4 51 47 58 38 17 63 33 23 28 43 12 69 70 33 17 12 50 18 18 36 45 2 67 4 45 20 4 33 38 29 45 8 22 58 39 71 38 32 53 35 19 53 31 29 51 35 4 63 18 33 26 47 70 9 64 62 63 30 15 1 35 28 16 40 20 14 50 33 19 38 30 27 55 10 16 46 47 7 55 12 53 26 56 33 29 55 25 17 48 43 21 43 18 24 63 27 68 46 38 33 35 10 18 11 27 5 9 58 35 70 36 36 39 47 2 10 66 47 5 18 21 44 71 51 57 3 22 7 56 55 28 25 14 40 16 24 48 37 66 50 24 45 18 39 53 55 ^ 165 1 15 62 35 29 15 40 19 76 67 4 5 71 46 61 26 8 77 48 1 23 12 60 40 24 44 33 29 42 73 66 49 61 20 30 1 54 52 42 39 64 23 65 37 24 20 11 26 66 22 77 22 57 7 38 57 33 61 73 7 64 1 49 35 76 14 27 21 45 68 38 58 73 13 72 47 73 33 8 66 23 38 4 56 77 47 10 71 13 20 31 41 6 51 3 18 17 61 47 14 48 76 46 28 34 43 1 56 4 25 7 65 41 1 34 37 23 59 59 27 26 13 15 14 75 60 14 1 28 59 26 65 61 16 23 17 28 6 19 2 35 49 30 29 48 2 63 73 59 1 3 76 41 11 19 18 43 54 63 67 51 4 9 78 60 66 ^ 181 0 18 19 84 17 12 10 57 18 77 51 52 16 39 74 49 52 63 38 72 2 15 64 83 62 49 56 11 26 68 58 83 33 23 50 63 71 53 27 84 22 39 41 52 58 11 64 7 60 45 70 22 5 73 38 30 30 48 21 75 80 40 21 8 53 9 26 30 34 81 71 71 51 23 75 33 41 23 32 5 8 66 40 72 40 16 66 45 14 48 34 21 41 27 3 55 27 37 23 41 65 4 57 51 74 22 19 75 42 16 19 46 16 10 48 20 19 37 41 14 57 9 17 55 38 5 60 7 46 20 43 36 39 52 20 10 62 45 23 46 7 35 75 29 70 35 36 34 25 12 15 84 26 10 6 71 29 79 33 32 25 59 76 82 64 58 7 8 19 41 74 2 53 65 24 1 55 51 36 21 79 7 ^ 184 1 60 66 66 6 3 9 73 12 7 40 70 18 71 70 65 51 14 14 27 50 9 87 81 50 22 19 40 37 16 79 12 34 37 76 82 10 61 7 81 49 67 26 45 82 50 81 63 45 69 31 31 76 51 9 59 34 51 54 34 83 10 33 51 86 81 82 69 18 8 22 64 19 86 62 58 33 37 17 34 5 29 83 42 76 50 54 66 39 9 1 36 43 17 65 6 35 56 72 71 83 88 10 1 8 87 22 6 21 78 25 89 43 62 40 55 85 31 89 74 63 46 28 24 26 31 17 7 8 27 19 12 85 17 20 27 77 10 2 54 80 17 52 74 76 69 78 11 20 80 4 29 24 85 75 18 39 23 70 83 29 57 67 72 70 33 4 15 46 42 2 69 13 53 33 69 64 33 64 14 40 69 59 78 54 ^ 193 1 68 43 95 53 38 58 55 28 20 16 67 48 17 86 32 44 68 67 28 16 14 79 25 15 72 67 50 80 18 30 10 75 1 60 45 87 78 28 95 49 63 70 59 26 6 51 73 60 65 18 26 8 87 5 58 31 25 57 40 46 78 57 34 78 61 36 66 57 38 80 22 32 68 71 30 74 37 81 66 77 66 55 2 51 24 93 61 40 68 45 61 12 63 24 89 59 52 72 43 20 20 69 36 40 88 46 9 62 55 77 84 20 18 6 77 15 52 39 75 3 26 4 85 17 62 29 11 92 46 58 29 59 28 42 80 71 96 2 49 85 37 63 4 61 14 2 53 87 25 86 6 75 76 93 41 39 93 92 42 56 41 63 26 28 18 77 11 50 78 79 1 12 12 91 29 13 58 5 56 92 66 59 4 39 47 95 5 5 62 33 13 80 27 ^ 203 1 35 28 11 7 20 7 17 3 3 30 89 13 65 56 66 63 22 82 16 31 55 56 77 91 91 71 101 13 10 85 101 95 17 99 98 91 33 14 20 48 32 7 64 29 38 35 25 4 95 23 34 1 85 81 23 31 96 71 84 50 15 79 47 25 51 45 35 66 19 61 60 9 31 93 64 70 30 42 86 53 1 71 46 42 22 38 96 10 99 34 76 26 55 73 63 63 97 23 92 81 64 46 1 30 31 35 86 91 88 64 87 16 37 69 84 94 60 100 3 47 52 8 71 87 57 29 76 43 18 45 46 15 65 12 44 42 66 60 15 68 19 58 39 62 76 9 92 101 57 32 4 34 15 41 62 32 89 71 43 35 31 41 21 17 82 33 96 27 62 29 82 57 46 62 15 24 99 37 83 40 52 46 56 80 98 3 91 74 6 27 7 58 94 10 41 79 97 84 77 74 26 99 35 ^ 212 1 26 101 17 91 45 97 80 59 102 30 68 4 85 9 4 39 16 18 85 70 11 87 62 72 78 38 3 41 53 82 82 35 18 13 94 64 52 39 77 59 26 9 65 46 64 98 32 29 86 79 16 63 54 76 56 98 16 98 78 22 72 33 103 104 52 84 12 65 15 85 101 97 84 31 51 26 100 100 38 80 13 2 78 7 24 44 84 103 27 7 28 16 33 99 25 103 54 14 42 62 87 92 27 22 42 5 52 100 84 73 72 63 24 48 56 52 23 5 17 76 31 1 95 58 43 60 50 62 30 23 35 79 20 35 3 72 32 45 51 87 41 84 27 79 77 70 102 15 54 15 100 8 52 69 105 3 30 84 42 93 66 89 69 74 24 33 42 97 4 38 99 106 13 93 6 106 74 100 54 45 21 59 56 37 9 50 32 75 79 31 77 9 61 1 8 68 6 60 81 7 100 99 14 61 48 25 73 26 70 72 94 34 ^ 233 0 11 98 110 88 35 110 35 64 49 88 93 28 85 6 78 65 90 52 24 97 51 39 51 59 23 1 3 49 33 11 78 27 35 55 64 5 102 4 70 25 56 58 38 66 11 31 96 66 104 59 41 86 58 29 79 41 40 72 51 12 92 34 52 44 69 104 21 97 89 96 48 21 4 61 40 28 67 34 23 85 44 22 62 52 33 84 23 30 73 74 4 79 12 81 47 80 53 47 89 40 19 80 62 34 61 29 41 95 43 1 70 63 55 53 18 19 13 48 10 19 89 49 4 52 53 56 76 10 8 104 77 15 28 38 75 109 3 85 90 8 40 8 93 90 43 39 14 60 17 36 78 56 105 80 35 75 36 58 82 50 100 98 45 74 13 66 95 72 71 95 34 14 98 72 33 38 37 52 6 14 107 59 3 29 61 67 98 92 5 93 17 98 36 87 41 75 71 57 88 17 25 91 84 3 58 20 92 69 51 50 36 31 14 25 18 30 18 1 41 104 30 82 59 87 70 34 96 28 47 62 81 103 48 ^ 234 1 63 90 108 108 102 64 82 88 4 111 76 97 22 1 108 41 34 91 33 20 25 24 26 8 83 11 31 7 85 109 106 4 105 85 68 28 33 99 53 8 16 12 11 74 17 83 66 70 16 30 9 67 68 34 24 81 47 92 72 47 37 33 38 92 17 8 28 88 22 62 69 32 89 75 3 72 96 85 13 105 24 38 37 94 115 83 72 108 114 24 93 76 103 60 99 102 9 43 10 59 95 46 33 93 15 26 69 44 2 86 107 55 45 61 65 92 66 9 55 39 70 83 29 98 67 13 111 15 20 31 62 8 2 51 20 19 33 44 14 115 71 112 97 10 41 28 53 51 26 57 15 38 98 55 106 22 56 31 50 95 107 110 84 70 10 108 96 73 100 25 36 55 88 71 63 96 30 90 96 79 22 7 30 23 28 59 89 8 51 99 47 86 34 18 43 65 98 104 107 49 7 79 71 8 57 21 29 80 2 74 78 44 57 9 61 22 13 68 52 91 74 98 43 30 58 68 95 101 72 102 76 42 99 61 ^ 249 0 27 117 45 119 80 2 59 52 8 76 20 94 102 69 96 42 46 106 67 9 110 89 71 69 34 31 15 85 16 29 100 82 37 62 68 95 108 44 23 114 34 36 56 93 11 30 96 12 31 67 14 114 14 66 70 30 81 46 53 119 85 6 104 47 92 72 70 5 70 15 115 68 105 33 97 13 85 106 14 61 29 22 86 45 57 69 91 38 38 28 66 13 60 95 103 3 15 5 113 38 23 62 5 65 94 107 73 104 37 47 102 117 3 78 35 7 95 56 78 45 52 28 46 43 37 32 53 19 55 29 47 97 76 115 83 71 11 45 62 73 99 116 2 24 116 7 28 41 2 29 37 52 23 5 118 79 31 57 89 61 24 101 78 50 93 73 41 7 33 45 47 24 1 48 73 36 3 25 87 46 28 108 54 68 53 67 119 28 36 118 104 42 88 27 112 4 74 85 1 63 39 97 71 74 75 76 10 49 12 79 11 50 103 118 94 117 118 37 27 12 94 60 28 51 47 82 110 17 15 105 23 52 43 12 21 22 81 41 12 74 90 42 108 117 98 67 4 69 85 ^ 243 0 76 81 26 101 13 68 62 106 87 19 98 32 81 63 79 93 31 121 123 75 52 11 66 41 54 87 38 5 104 62 51 38 55 29 31 120 44 16 48 94 46 105 91 66 78 27 43 6 64 2 55 79 75 84 113 22 4 113 109 31 33 17 96 11 29 63 98 103 107 116 34 14 9 95 38 18 51 75 33 109 118 55 66 4 76 7 75 70 82 74 23 1 26 69 40 112 99 47 65 31 70 119 52 103 88 85 86 28 16 12 76 25 22 78 64 21 86 27 61 77 72 108 2 18 106 119 121 54 16 85 72 2 73 26 88 66 60 80 35 24 117 63 24 44 67 52 122 119 33 72 16 99 98 69 54 19 42 28 53 114 32 117 81 100 57 49 123 56 21 68 80 53 95 1 45 95 107 98 87 1 27 24 99 116 16 67 1 113 91 84 25 40 25 72 3 28 90 87 112 80 16 117 45 77 36 90 105 59 88 122 64 108 108 71 98 18 50 115 93 105 77 35 6 46 55 47 102 4 26 87 111 120 81 113 4 57 105 3 84 94 115 61 73 ^ 255 1 91 47 51 9 57 9 55 94 61 61 68 46 107 6 35 81 114 78 96 74 14 89 73 67 67 69 113 107 11 98 113 109 20 92 17 67 70 88 57 10 124 9 60 122 93 91 45 7 15 24 51 5 98 115 24 49 90 104 117 66 128 94 64 80 12 43 91 46 111 59 58 77 30 14 88 60 123 68 41 44 68 40 104 118 41 43 93 90 105 92 16 127 26 54 125 114 79 71 24 48 21 25 118 40 103 49 91 44 67 65 25 119 109 18 48 23 69 112 38 61 64 87 84 104 119 110 122 92 22 1 8 83 34 100 32 62 41 46 112 34 102 76 56 39 4 127 30 13 19 110 124 7 16 128 95 4 124 11 104 116 126 49 95 3 55 96 70 90 101 4 122 96 75 118 39 128 99 92 18 42 20 87 83 35 75 111 61 67 71 28 101 9 56 34 105 95 71 23 73 71 26 57 15 23 76 55 99 89 128 98 117 68 43 88 62 38 62 39 2 83 36 15 26 60 128 96 73 74 10 1 12 42 22 2 77 33 33 32 57 13 14 82 57 12 39 3 58 80 14 87 85 44 69 109 119 ^ 283 0 102 55 53 41 60 88 25 67 58 76 44 22 68 118 108 40 95 96 81 90 85 28 77 18 11 37 72 93 60 110 124 119 95 131 91 37 109 126 8 73 69 72 80 17 83 5 76 20 32 15 10 1 103 18 22 116 98 9 51 104 102 44 33 15 12 24 31 89 1 6 28 101 8 64 72 106 30 5 52 89 111 39 108 64 85 17 57 124 22 105 78 115 3 40 108 66 108 77 128 103 44 35 38 13 95 10 111 63 98 117 61 51 126 69 96 70 70 59 39 13 97 33 112 2 77 7 123 70 83 29 66 67 49 79 19 104 115 14 60 2 55 40 71 33 28 114 51 91 17 46 45 128 57 87 62 25 115 38 50 55 90 74 8 51 102 79 43 94 36 122 94 12 41 36 25 104 91 24 7 99 80 30 126 32 63 122 107 114 27 28 79 41 12 35 51 115 122 70 22 79 65 2 88 27 17 59 15 23 44 57 5 65 6 26 78 80 125 93 84 100 45 22 129 68 36 111 74 118 11 50 42 120 47 21 8 86 112 26 67 60 99 45 93 47 8 38 59 52 56 124 20 82 18 117 24 18 46 106 19 117 26 41 47 45 130 7 15 1 4 5 100 10 85 50 44 11 48 92 119 108 42 118 125 ^ 272 0 8 61 99 70 96 20 87 123 134 82 22 2 110 118 33 86 5 7 5 94 56 15 60 96 54 13 22 55 99 4 25 105 17 37 69 10 38 117 117 30 70 13 9 109 115 62 94 52 66 117 100 135 7 75 23 5 81 110 31 118 29 1 62 11 41 88 109 119 102 37 3 30 123 47 31 56 134 29 124 116 118 99 21 56 77 91 23 37 135 81 44 51 67 95 51 133 30 57 67 116 122 48 100 7 132 97 106 69 93 4 95 125 102 103 119 81 57 133 96 37 118 50 117 113 81 127 17 45 103 32 121 129 60 43 65 127 30 36 132 110 52 53 35 71 12 76 22 72 130 112 99 76 26 21 73 63 63 97 23 58 115 132 114 1 132 31 35 18 23 54 30 53 118 37 35 84 94 60 100 3 47 18 110 105 87 57 63 76 43 52 45 46 49 65 12 10 42 66 60 117 34 19 92 5 28 76 9 126 101 125 32 38 34 15 7 62 32 21 3 43 69 31 109 123 51 116 135 130 129 130 63 14 57 80 62 15 126 31 105 83 108 120 80 124 46 98 105 91 6 6 27 7 58 128 78 7 79 63 84 77 74 128 65 61 95 121 17 24 123 117 51 122 ^ 284 0 44 71 43 20 126 58 53 47 98 18 19 119 93 29 70 39 94 112 44 115 135 98 82 10 67 29 102 113 68 80 19 75 1 91 114 87 80 7 40 37 86 120 16 104 136 117 82 138 32 65 114 119 137 121 8 12 46 126 26 119 73 130 60 76 113 100 14 133 26 116 34 120 80 95 84 53 15 24 44 51 4 10 23 77 24 99 66 37 54 63 42 136 21 34 76 5 17 128 101 1 59 40 113 112 32 97 31 93 105 79 91 18 39 1 103 132 51 68 124 111 13 97 43 128 69 84 85 72 15 12 26 87 16 16 92 101 13 77 4 118 89 103 56 42 16 60 44 39 126 46 18 83 93 41 105 3 82 106 115 91 6 4 54 115 15 120 109 113 48 41 9 95 20 62 67 105 111 25 132 7 116 46 138 44 83 61 124 131 35 107 6 109 81 114 67 41 137 77 56 74 73 34 12 14 69 52 11 98 47 54 83 81 6 1 15 88 35 139 80 83 49 89 27 47 130 92 133 87 51 112 76 49 109 49 57 93 73 22 117 50 64 58 97 139 36 131 111 133 58 33 8 88 55 38 90 46 30 118 57 29 82 74 41 117 38 46 94 92 5 105 15 117 70 103 68 60 120 48 21 110 85 40 81 66 ^ 291 0 46 113 52 134 79 74 64 57 18 23 9 52 8 16 103 57 138 59 59 65 92 2 7 130 92 8 34 40 86 131 140 100 112 4 42 1 110 108 43 37 15 67 19 35 94 61 130 98 35 88 34 65 104 56 126 118 50 87 10 81 109 90 86 118 32 6 114 88 39 38 39 62 3 12 134 72 137 35 75 81 115 106 140 112 11 123 41 103 45 95 84 71 107 13 26 110 96 62 16 109 84 59 53 38 27 8 28 13 32 137 17 138 41 122 36 99 65 99 83 36 112 29 49 70 96 126 136 131 116 3 18 17 126 142 14 37 141 141 123 42 13 20 83 42 139 83 54 49 58 42 7 137 29 48 16 121 127 34 52 140 106 128 58 36 124 83 24 69 54 61 112 17 6 95 97 24 57 86 124 59 71 119 67 1 109 54 68 49 57 132 32 5 71 113 40 80 104 75 106 133 31 126 130 104 62 9 39 44 66 116 141 135 96 132 19 41 121 126 124 77 8 4 60 82 6 101 124 89 51 123 48 40 85 77 21 112 10 69 66 115 87 16 108 30 84 65 80 103 32 131 134 73 47 10 63 39 50 93 37 135 114 69 48 34 58 23 27 133 37 9 40 98 41 115 99 70 83 29 42 67 133 55 79 80 91 122 12 2 115 112 47 ^ 293 1 33 13 99 138 1 42 89 118 87 113 99 12 134 142 100 38 5 55 75 14 110 108 42 64 130 79 138 62 64 69 57 11 123 25 59 16 111 94 24 65 30 51 119 48 107 92 84 69 28 136 143 54 20 6 70 47 142 64 4 65 59 73 99 134 146 102 125 116 57 137 137 72 48 128 78 5 80 63 54 85 30 22 129 68 21 21 74 28 128 107 27 60 2 93 95 71 37 11 37 15 39 102 3 104 65 80 59 52 113 34 20 67 60 27 81 135 46 106 106 102 68 128 17 15 100 124 15 43 136 122 100 67 142 35 14 53 120 2 89 93 99 73 9 122 39 77 15 96 90 43 79 134 60 92 105 55 96 31 119 77 97 72 23 140 38 30 43 83 136 88 107 117 72 109 118 58 91 119 73 95 100 59 138 123 54 49 143 50 133 66 106 45 80 88 42 93 5 59 77 101 74 110 104 40 92 19 77 76 86 102 129 3 144 101 139 134 56 90 18 91 94 85 55 10 137 11 58 1 107 113 70 22 7 56 29 143 111 8 46 45 116 122 129 89 7 121 53 95 14 49 118 62 125 91 37 97 15 35 100 63 140 63 50 51 58 26 127 6 45 59 102 121 114 85 141 135 10 72 19 106 66 66 41 53 13 38 1 21 103 50 108 46 119 ^ 297 1 46 31 132 112 28 63 124 97 129 43 40 72 99 107 132 137 96 139 99 145 121 144 118 37 81 39 94 60 55 109 47 109 110 75 42 12 139 137 43 128 106 107 19 126 12 101 148 127 15 117 125 125 62 96 13 76 70 96 101 110 138 8 95 76 143 17 32 97 79 149 39 31 94 123 21 41 135 55 84 70 33 135 118 50 62 121 81 1 45 144 93 60 5 64 137 8 105 91 82 67 27 113 119 53 18 98 79 48 84 32 135 128 5 1 20 76 17 85 108 72 36 141 140 49 150 105 104 3 149 14 54 18 148 64 49 125 37 28 28 101 22 104 91 32 82 117 12 114 69 58 2 58 115 9 108 47 59 65 14 92 7 4 86 98 16 82 92 95 38 94 10 10 48 97 104 66 115 97 142 115 122 119 40 97 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 40 122 84 108 22 142 140 99 44 15 54 8 42 125 150 130 21 79 124 62 46 119 15 29 91 57 150 42 138 71 61 68 80 114 6 1 70 121 18 35 113 56 87 86 10 73 14 29 41 72 89 1 133 87 101 123 59 90 142 77 133 52 78 48 34 138 134 27 17 60 131 147 61 93 148 39 132 49 62 71 36 91 4 139 49 100 120 43 113 144 30 94 73 127 40 125 ^ 313 1 35 97 95 76 105 88 32 138 30 69 61 40 47 21 107 6 39 81 114 53 125 53 147 14 4 73 146 96 98 13 136 11 98 117 138 153 67 146 71 99 88 7 139 24 13 35 47 97 145 74 36 119 3 51 84 48 119 53 49 15 79 17 120 103 148 64 30 41 97 120 75 111 63 58 131 134 18 13 10 48 18 16 48 43 15 54 18 41 47 122 144 80 92 145 77 1 33 89 54 46 78 48 21 54 43 40 53 24 16 73 42 94 29 44 34 151 152 23 123 12 142 140 43 37 88 29 19 35 72 96 151 130 62 112 34 36 91 120 50 112 138 2 105 60 68 137 131 5 17 19 139 74 11 120 78 149 58 128 15 104 16 126 78 20 57 134 71 49 90 76 108 126 100 54 68 39 132 153 42 147 146 124 62 87 35 75 61 65 46 100 82 105 113 31 63 5 95 54 71 77 127 150 80 36 144 2 130 59 74 39 3 152 121 122 18 117 12 117 141 118 135 62 36 69 5 39 53 150 52 153 143 30 66 96 126 131 56 137 8 7 86 142 14 7 111 141 93 136 137 134 43 12 89 23 44 9 152 146 121 97 19 38 110 91 67 14 32 110 66 68 8 130 84 73 118 59 24 41 72 121 150 55 37 138 27 104 66 124 9 51 109 47 125 109 148 8 29 47 72 146 149 61 93 10 20 54 15 76 133 125 106 110 67 ^ 330 0 23 9 26 136 27 51 115 122 44 106 6 146 108 113 85 51 8 96 47 56 137 62 59 89 143 71 140 14 85 156 139 99 154 30 53 115 35 147 108 148 58 52 28 103 19 92 95 152 152 10 11 13 155 67 11 83 101 69 153 152 45 141 14 120 129 140 119 59 2 89 73 70 83 29 16 67 81 29 1 54 65 96 117 2 37 47 128 33 3 89 108 98 139 49 78 27 103 39 119 94 132 90 38 132 55 65 131 90 58 2 54 100 69 118 22 44 19 7 148 93 25 29 123 81 64 131 55 30 1 89 38 97 82 64 9 28 86 123 151 10 133 40 154 102 4 111 65 9 63 59 124 116 72 105 76 57 137 97 32 145 108 78 112 50 43 34 75 20 22 129 68 11 118 74 125 118 57 17 20 129 53 65 61 144 1 17 142 156 52 100 54 15 20 59 52 63 131 20 57 124 31 125 46 106 76 92 8 98 154 152 80 114 15 140 136 112 100 17 92 25 151 150 80 99 69 83 49 43 156 102 19 57 122 96 30 3 39 134 40 32 75 5 76 127 138 99 17 57 52 150 130 18 127 33 23 116 107 78 77 77 42 69 68 48 41 69 33 75 40 49 128 103 4 146 93 10 83 66 96 152 30 38 12 33 5 39 47 41 34 60 74 20 42 156 67 46 56 102 89 3 124 81 99 104 56 50 8 61 74 55 15 87 108 28 138 47 93 60 2 124 46 126 103 91 145 36 25 116 122 51 ^ 322 0 75 7 107 158 81 105 154 90 20 125 77 114 69 92 7 58 21 98 154 50 128 149 117 127 153 45 3 18 121 86 29 71 79 101 2 5 22 143 10 27 53 146 157 148 112 33 22 80 123 24 147 1 112 82 159 63 74 97 109 33 151 32 89 87 132 117 46 129 59 115 91 114 118 37 21 9 94 60 25 89 47 79 110 55 12 143 99 87 43 88 56 57 160 76 12 71 128 77 146 117 95 105 42 66 3 76 20 76 101 100 118 149 45 26 143 148 32 57 39 129 19 31 84 123 1 152 135 5 54 30 13 125 68 30 62 101 51 142 5 94 83 20 116 24 107 109 105 91 42 17 27 93 69 3 139 68 79 38 84 2 85 128 126 122 131 46 17 35 98 42 26 111 100 29 120 55 84 114 109 145 14 18 138 14 9 85 7 18 129 91 2 94 51 133 82 87 123 64 39 8 103 38 75 110 78 7 9 45 115 42 138 135 86 78 16 62 52 75 159 54 151 121 149 77 74 16 85 47 102 105 82 119 10 67 137 153 148 135 28 49 26 151 153 36 80 11 130 113 24 44 30 102 24 58 133 122 140 99 24 156 54 119 42 115 140 90 132 19 94 2 157 99 136 19 71 7 130 153 108 51 21 58 70 74 137 1 40 111 149 5 103 6 27 76 141 23 125 140 1 72 29 152 103 87 51 93 29 80 132 77 123 153 68 159 14 98 114 158 121 158 81 131 ^ 322 0 35 93 109 125 119 10 10 19 135 26 4 74 135 35 120 129 113 92 17 29 47 88 14 159 149 87 45 36 75 68 22 138 20 59 61 144 151 11 107 6 153 81 114 43 85 157 97 148 118 73 126 56 58 137 96 11 98 67 98 103 57 146 21 59 88 151 139 148 127 25 17 47 115 34 160 109 107 51 64 28 69 13 49 149 69 141 90 93 118 64 10 1 67 80 35 111 13 58 101 124 132 147 154 18 162 6 162 33 5 34 142 41 161 82 114 70 92 145 57 155 137 114 79 44 36 48 48 21 14 13 40 33 14 150 33 32 54 143 14 4 101 142 23 93 136 132 120 147 17 38 163 143 5 52 46 151 130 32 72 34 124 150 51 100 112 128 126 65 10 28 87 81 159 131 19 99 54 125 110 58 119 28 78 129 104 140 126 38 154 27 114 61 153 90 66 98 76 50 158 48 39 82 123 22 147 136 114 52 37 35 75 41 15 150 60 52 55 103 21 23 129 95 24 71 47 97 130 50 140 144 106 100 9 64 19 117 122 71 92 8 77 156 97 121 98 85 2 36 39 109 143 23 120 156 133 93 154 36 66 116 131 160 127 162 161 46 142 14 141 81 141 63 86 117 104 3 146 39 127 34 133 102 106 91 57 9 28 60 61 7 158 12 80 26 8 122 80 44 63 68 49 158 21 32 81 150 15 141 108 161 64 46 124 123 31 99 27 105 109 98 112 144 ^ 336 1 34 161 107 149 48 67 138 109 156 104 37 133 60 80 84 81 160 9 16 96 164 1 95 112 4 86 163 116 98 103 55 31 8 56 37 36 127 32 9 89 103 31 100 161 85 106 119 89 154 43 115 162 137 108 128 38 42 155 103 9 62 65 102 122 10 138 160 125 47 158 43 91 69 123 132 35 121 4 110 89 130 69 29 139 69 53 70 83 29 163 67 41 9 108 34 45 76 87 2 144 164 98 33 160 79 78 48 89 9 38 134 93 146 79 54 122 80 38 112 55 55 101 70 8 129 44 70 59 98 149 24 136 124 138 63 25 166 83 51 34 91 45 30 118 59 28 87 72 44 116 28 36 103 101 113 10 114 62 111 71 65 126 53 19 114 86 42 85 36 57 137 57 159 95 88 78 72 20 23 14 65 10 22 129 68 1 68 74 75 108 7 7 147 109 13 35 51 104 158 164 122 126 2 50 4 132 127 59 52 13 81 20 47 107 74 148 115 46 106 46 82 115 68 144 142 60 104 15 90 136 102 100 134 42 15 141 100 40 49 49 73 166 13 156 82 166 37 82 96 137 130 166 134 20 139 45 122 56 107 98 79 124 17 32 130 120 165 77 23 130 96 67 68 47 37 12 29 18 38 158 19 160 55 147 39 118 83 121 96 43 137 33 66 86 112 147 155 149 140 5 19 17 148 161 10 44 159 146 57 16 26 102 49 3 104 61 59 74 56 10 165 31 54 25 142 157 37 58 165 128 154 73 50 149 94 137 ^ 330 1 61 51 65 132 23 169 116 122 14 66 7 98 131 72 69 127 72 163 125 68 69 51 47 159 31 164 71 118 50 83 113 81 127 153 45 137 134 121 68 163 26 43 65 127 166 138 98 144 18 53 137 139 148 76 158 4 62 78 167 102 144 94 55 141 63 29 97 91 24 115 166 80 69 132 99 1 120 23 88 64 87 118 37 137 152 94 60 168 71 47 52 110 37 155 125 63 42 43 52 11 12 151 31 12 44 110 32 128 117 68 87 24 39 164 76 145 58 101 91 100 140 151 143 130 32 21 3 111 1 31 75 123 153 116 135 130 27 164 165 116 23 12 62 83 24 133 139 49 74 154 80 158 80 64 105 91 6 142 27 75 24 128 112 41 79 29 84 145 40 128 99 95 95 19 17 160 89 15 17 84 64 11 93 10 66 78 73 127 148 18 129 139 143 49 150 9 84 82 154 85 15 88 82 60 87 19 12 133 58 20 39 65 51 141 134 27 70 167 120 117 86 60 16 44 16 57 132 18 142 85 104 59 47 141 58 2 66 96 46 119 153 40 110 126 103 90 144 13 26 106 144 80 145 134 103 95 24 44 21 84 140 13 97 104 140 99 6 147 54 83 42 106 131 54 96 135 67 118 121 81 109 10 53 132 112 117 81 33 155 49 61 38 119 1 13 102 131 148 94 131 143 67 123 148 89 104 135 72 145 152 76 87 6 66 2 71 123 77 114 108 59 123 166 62 96 140 94 149 116 169 ^ 349 0 125 17 93 82 80 110 156 147 156 99 154 4 29 90 163 120 84 113 56 8 157 29 61 169 141 113 78 48 50 13 138 11 50 61 99 106 2 107 6 117 81 114 34 49 112 52 130 82 73 108 20 22 110 60 11 98 22 62 58 48 146 149 23 88 142 139 121 91 16 163 2 88 171 133 100 62 51 46 10 24 150 49 131 60 114 63 84 91 64 165 138 40 44 172 111 141 58 74 115 96 129 145 164 153 170 126 24 169 16 115 41 125 46 87 61 92 145 39 155 92 78 70 35 27 21 48 21 151 159 40 15 5 132 170 23 18 107 160 150 56 133 23 66 109 123 102 102 172 166 145 116 151 34 1 151 130 5 36 34 97 114 15 82 128 112 119 99 29 138 165 42 36 159 95 19 63 36 89 101 40 92 1 33 93 104 113 126 2 136 96 52 108 90 57 89 31 5 113 30 39 37 96 4 147 127 105 43 165 35 75 23 143 105 24 25 10 94 12 160 102 95 170 71 20 70 112 23 95 144 61 73 137 55 1 81 95 26 65 172 41 147 79 103 80 40 121 36 12 64 98 169 93 111 115 48 127 9 39 107 131 115 118 162 161 10 142 14 123 54 141 36 41 99 77 140 128 167 82 25 106 57 70 64 21 19 15 34 126 149 167 53 163 127 86 35 8 54 23 40 140 3 169 45 150 152 96 81 143 28 28 124 87 13 90 9 87 109 53 67 164 28 131 89 149 42 55 126 79 132 74 19 133 30 68 72 75 148 9 10 72 152 144 83 106 153 74 163 98 152 ^ 375 1 94 28 13 8 20 28 18 118 5 140 89 67 171 64 152 85 61 101 80 154 149 34 115 135 128 108 110 20 33 128 103 35 38 57 95 10 111 151 98 29 149 7 82 69 96 114 26 103 171 101 53 121 24 2 121 51 35 70 83 29 154 67 5 167 63 16 27 58 60 2 99 128 71 33 160 70 51 3 44 149 2 89 84 101 43 18 113 71 38 94 55 46 74 52 139 102 35 43 50 80 122 6 100 88 129 36 25 148 47 24 7 55 36 30 82 32 19 78 63 26 71 28 167 85 56 167 95 159 78 26 66 35 65 90 44 159 105 59 15 67 57 137 21 132 50 70 78 36 169 5 172 56 1 22 129 68 168 23 74 30 99 138 174 120 91 153 8 42 68 158 155 104 99 133 5 135 96 82 59 52 144 36 20 38 62 29 112 106 46 106 19 73 70 41 135 133 42 95 15 45 136 93 100 98 173 6 132 55 4 4 31 64 130 162 156 64 157 19 46 96 92 103 139 134 2 94 18 86 38 89 62 61 79 157 14 112 111 156 32 14 85 78 31 59 20 1 161 169 149 29 122 150 133 37 102 30 109 65 85 51 174 110 164 66 77 76 111 119 131 95 5 1 166 103 134 141 17 158 123 137 48 165 175 102 13 3 86 43 23 47 56 150 165 4 36 174 115 157 168 13 147 119 109 55 41 140 67 27 31 27 53 126 17 163 116 122 160 60 7 92 113 66 45 109 60 151 125 62 39 39 17 153 13 152 53 94 50 53 89 57 127 153 45 119 104 121 56 145 172 19 41 103 166 108 68 126 12 53 131 127 148 52 134 168 50 48 155 72 132 82 37 129 63 175 160 ^ 366 1 73 15 79 139 71 51 132 81 135 111 166 61 37 60 118 37 92 134 94 60 150 53 47 25 110 19 137 107 27 176 43 16 145 146 142 165 12 17 92 166 110 117 41 69 6 12 164 76 109 40 101 82 82 131 134 115 143 112 32 164 146 93 162 31 66 123 144 80 135 94 137 156 107 157 173 62 65 176 124 112 4 65 127 44 131 53 19 105 91 149 106 27 57 158 92 85 14 79 20 84 127 174 128 72 68 59 171 17 124 80 167 8 57 28 172 66 144 48 42 37 109 121 18 120 103 116 13 132 39 73 145 76 158 43 82 33 51 153 164 97 13 2 3 20 24 114 98 9 25 131 102 99 86 42 16 26 159 39 105 161 133 49 59 41 20 105 31 136 30 87 10 119 135 13 83 99 58 45 99 156 26 61 135 143 80 118 107 76 77 24 44 12 66 95 147 61 86 140 99 167 138 54 47 42 97 122 18 60 90 40 73 85 63 82 1 35 96 94 81 54 15 128 40 52 2 101 1 165 93 113 130 85 95 98 58 105 112 53 68 108 72 100 152 49 87 140 39 154 62 114 77 105 63 50 87 157 26 78 122 67 140 71 170 119 5 93 64 50 104 144 129 138 75 130 4 178 60 139 120 54 113 32 2 133 17 43 163 129 89 72 149 155 30 38 7 138 5 44 61 69 76 175 107 6 93 81 114 28 25 82 22 118 58 73 96 175 177 92 36 11 98 171 38 28 42 146 125 178 88 136 139 103 67 10 151 151 70 153 115 94 32 51 34 177 173 132 49 119 54 96 45 78 73 64 159 120 22 20 154 111 117 58 56 109 72 143 ^ 372 1 136 146 144 170 90 15 169 180 88 41 89 10 60 52 92 145 21 155 47 42 61 26 18 176 48 21 124 141 40 179 178 114 143 14 164 71 142 132 11 124 23 39 82 114 84 57 163 130 127 89 133 16 138 151 130 160 34 70 78 161 64 92 112 110 72 175 102 138 179 173 159 59 19 27 18 53 92 22 65 156 170 57 104 86 126 148 118 155 78 43 63 90 48 80 168 142 68 12 39 174 69 168 147 118 96 34 129 35 75 5 107 60 170 180 147 85 3 133 75 95 152 71 175 43 94 178 50 144 16 46 101 46 165 45 68 163 38 172 5 138 61 85 62 177 76 36 167 19 53 151 66 66 97 3 100 164 12 98 131 70 109 162 161 156 142 14 105 27 141 9 178 81 50 113 110 131 37 16 79 12 34 37 167 173 10 152 7 81 140 158 26 136 82 50 172 154 45 160 31 122 167 142 9 150 125 51 54 125 174 10 124 51 177 81 173 69 109 8 22 155 19 86 62 149 33 37 108 34 96 29 174 133 167 50 54 66 130 9 1 36 134 108 65 97 126 56 163 71 83 88 10 1 8 178 22 6 112 169 116 89 43 153 40 146 85 31 89 74 154 137 28 115 117 122 108 98 8 27 110 103 176 17 20 27 77 10 93 145 80 17 143 165 76 69 78 102 20 91 171 95 29 115 176 166 109 39 23 70 83 29 148 67 163 161 33 4 15 46 42 2 69 104 53 33 160 64 33 155 14 131 160 59 78 71 19 176 107 65 38 82 55 40 56 40 115 84 29 25 44 68 104 176 76 64 123 18 25 136 23 6 171 31 30 30 58 14 13 72 57 14 41 177 ^ 363 0 135 69 16 167 79 143 46 178 26 3 65 58 36 135 97 35 175 51 152 57 137 173 108 10 54 78 4 153 173 164 48 177 22 129 68 168 167 74 174 91 106 174 96 75 129 168 34 36 158 147 88 75 101 149 103 64 42 59 52 112 180 20 30 22 173 80 98 46 106 179 65 30 17 127 125 26 87 15 5 136 85 100 66 141 182 124 15 156 148 15 56 98 146 156 48 149 3 14 96 52 79 115 134 170 54 178 54 22 73 30 45 39 133 182 96 103 148 176 6 45 62 183 51 180 153 145 145 117 21 90 118 109 21 62 22 101 49 53 11 142 86 132 66 69 44 79 87 115 55 5 169 150 63 110 109 177 150 91 129 40 149 159 102 165 3 70 27 175 23 56 126 165 164 20 158 91 157 136 157 131 111 69 39 33 132 43 19 175 179 37 118 9 155 116 122 128 52 7 84 89 58 13 85 44 135 125 54 183 23 161 145 173 136 29 62 50 13 57 25 127 153 45 95 64 121 40 121 140 171 9 71 166 68 28 102 4 53 123 111 148 20 102 160 34 8 139 32 116 66 13 113 63 143 97 63 10 59 124 66 41 132 71 115 106 151 46 22 45 118 37 67 124 94 60 140 43 47 10 110 9 127 97 7 156 43 180 125 126 137 145 12 2 82 146 100 117 26 59 180 181 164 76 89 30 101 77 72 126 114 95 143 102 32 149 131 83 157 31 61 123 139 60 135 74 169 122 151 102 137 168 62 55 166 119 97 163 60 112 24 116 38 178 105 91 134 86 27 47 138 72 70 183 79 15 84 117 154 128 57 53 39 161 88 ^ 393 1 92 72 151 33 183 164 42 112 32 10 5 93 97 18 112 71 92 168 116 179 186 65 137 68 134 3 82 9 19 121 148 65 160 173 158 167 90 66 180 172 99 86 83 86 26 16 10 135 23 81 137 125 17 19 25 183 73 7 104 185 79 165 119 119 176 59 75 18 5 59 132 26 21 127 119 80 94 83 52 61 24 44 4 50 55 115 29 70 140 99 159 130 54 15 42 89 114 173 28 50 16 33 53 47 58 180 19 64 78 49 30 186 104 32 44 157 85 1 149 85 97 114 77 63 58 50 89 80 21 36 84 72 60 152 25 87 108 15 138 54 106 77 97 23 42 55 149 181 62 106 43 132 31 138 111 176 93 40 10 96 128 105 114 43 98 4 146 20 107 120 14 113 181 101 1 19 155 113 57 64 117 131 6 22 186 138 184 36 61 29 36 175 107 6 61 81 114 20 180 42 169 102 26 73 80 151 153 68 4 11 98 139 6 175 34 146 93 154 88 128 139 79 35 2 135 119 46 129 91 86 179 51 18 169 141 108 49 103 46 72 21 70 49 64 151 96 185 175 130 111 85 58 32 101 40 101 131 136 139 170 70 10 169 175 73 41 69 177 45 47 92 145 11 155 22 22 56 21 13 166 48 21 109 131 40 174 178 104 128 9 149 51 132 122 173 119 23 24 67 109 74 32 158 110 117 74 123 6 118 151 130 150 167 34 55 58 146 54 72 112 105 57 160 82 123 159 153 159 39 19 7 8 33 87 12 50 146 150 37 104 71 126 133 108 145 68 38 38 90 43 75 148 122 43 2 39 154 54 163 147 113 91 29 109 35 75 182 87 35 155 170 127 80 185 118 60 95 142 71 165 28 84 168 25 144 178 31 81 41 160 25 53 143 ^ 381 1 14 172 163 130 45 69 46 145 36 36 151 169 13 135 42 26 81 153 76 148 178 90 131 30 101 162 161 132 142 14 89 3 141 175 146 65 26 89 94 99 187 8 55 162 2 13 143 173 2 120 173 41 132 150 2 112 42 18 140 130 37 128 23 106 159 118 167 150 101 11 30 109 150 184 124 19 169 73 165 53 109 158 172 147 11 46 38 149 25 21 92 184 64 179 158 133 135 34 38 58 114 9 183 4 118 76 49 89 102 40 163 47 75 80 176 175 8 154 14 180 104 153 84 89 11 129 8 138 85 181 73 66 154 121 20 115 93 114 108 82 182 19 86 103 176 183 186 177 53 10 69 137 56 1 135 141 68 69 54 86 12 75 171 87 187 107 144 150 93 23 7 70 83 29 140 67 139 153 183 178 189 30 18 2 29 72 29 33 160 56 9 123 164 107 136 19 70 31 177 152 99 57 38 66 55 32 32 24 83 60 21 1 36 52 80 168 44 32 115 184 25 120 181 172 155 189 22 30 26 180 5 64 49 188 1 28 111 57 176 167 67 131 22 160 186 169 65 34 30 117 91 17 163 39 134 57 137 155 90 170 42 78 170 141 167 158 42 177 22 129 68 168 143 74 150 85 82 174 78 63 111 156 28 12 158 141 76 57 77 125 79 40 12 59 52 88 156 20 24 182 149 56 92 46 106 167 59 189 121 119 14 81 15 165 136 79 100 42 117 182 118 175 138 124 3 50 74 134 156 36 143 181 180 96 22 61 97 134 164 24 166 30 10 61 6 33 9 115 176 84 97 142 152 15 50 165 45 168 135 133 127 93 15 66 94 91 9 32 16 95 37 29 171 118 68 108 66 63 20 55 186 ^ 396 1 97 10 5 160 132 18 83 73 159 141 55 120 31 131 141 102 138 3 52 9 148 189 56 99 165 146 2 140 64 157 100 121 113 102 24 21 24 123 16 10 139 152 19 109 146 116 122 92 43 7 75 62 49 170 58 26 117 125 45 147 5 125 136 155 118 2 26 50 161 21 182 127 153 45 68 19 121 22 94 104 144 166 35 166 23 176 75 188 53 114 93 148 177 66 151 16 156 121 180 98 48 179 95 63 107 97 45 1 23 97 57 23 132 53 79 97 124 19 188 18 118 37 22 106 94 60 122 25 47 176 110 184 109 79 164 120 43 153 89 90 128 109 12 168 64 110 82 117 192 41 171 163 164 76 53 12 101 68 54 117 78 59 143 84 32 122 104 65 148 31 52 123 130 24 135 38 151 95 142 93 101 159 62 37 148 110 70 127 51 85 181 89 11 142 105 91 107 50 27 29 102 36 43 165 79 6 84 99 118 128 30 26 3 143 17 68 66 139 187 15 165 158 24 88 20 179 174 81 79 18 106 47 74 150 104 179 162 59 131 62 116 166 82 184 188 97 136 41 136 167 140 143 175 72 42 174 148 75 74 71 86 14 16 191 117 11 63 119 119 186 182 13 171 49 182 80 167 73 147 119 107 164 41 57 181 168 29 114 26 184 121 101 80 76 65 34 49 24 44 191 38 25 91 5 58 140 99 153 124 54 184 42 83 108 155 4 20 191 3 29 35 40 180 7 40 66 25 12 180 86 26 38 139 73 1 137 79 85 102 71 39 28 44 77 56 190 12 66 72 30 152 7 87 84 190 126 48 100 77 91 186 36 31 143 163 50 94 25 126 1 114 105 170 93 22 173 90 116 87 96 19 74 4 122 183 83 120 177 113 169 181 77 182 1 149 186 ^ 384 1 25 56 85 107 177 6 186 138 184 28 61 184 191 175 107 6 29 81 114 12 156 2 137 86 189 73 64 127 129 44 167 11 98 107 169 143 26 146 61 130 88 120 139 55 3 189 119 87 22 105 67 78 147 51 2 161 109 84 49 87 38 48 192 62 25 64 143 72 169 151 106 111 53 58 8 93 8 85 123 120 131 170 38 2 169 167 49 41 37 153 21 39 92 145 190 155 177 185 48 13 5 150 48 21 85 115 40 166 178 88 104 1 125 19 116 106 141 111 23 43 101 58 187 150 78 101 50 107 185 86 151 130 134 143 34 31 26 122 38 40 112 97 33 136 50 99 127 121 159 7 19 170 187 1 79 191 26 130 118 5 104 47 126 109 92 129 52 30 193 90 35 67 116 90 3 181 39 122 30 155 147 105 83 21 77 35 75 174 55 190 131 154 95 72 185 94 36 95 126 71 149 4 68 152 180 144 146 7 49 33 152 188 29 111 194 172 148 125 35 59 36 125 11 36 141 149 183 125 27 1 71 133 61 138 168 85 131 5 96 162 161 117 142 14 79 183 141 165 126 55 11 74 84 79 167 3 40 142 177 193 128 173 192 100 163 16 127 145 182 97 17 193 120 115 32 108 18 96 154 103 152 150 86 181 15 99 135 179 124 194 164 68 160 43 109 138 152 142 6 21 23 149 20 11 82 164 44 159 148 133 115 24 28 53 104 9 183 179 108 56 39 84 87 30 163 32 70 75 166 170 8 139 9 175 99 143 64 89 186 114 183 133 85 161 63 61 154 111 15 115 78 109 108 72 177 14 71 103 176 173 176 157 38 10 54 132 41 186 130 126 63 69 39 76 7 65 171 82 172 102 124 140 83 113 ^ 396 1 189 70 83 29 132 67 115 145 151 170 181 14 192 2 187 40 5 33 160 48 183 91 132 83 112 177 62 189 153 128 91 49 38 50 55 24 8 8 51 36 13 175 28 36 56 160 12 107 168 25 104 157 156 139 165 14 30 192 164 195 56 41 180 159 28 79 41 144 167 51 115 188 136 154 145 65 2 22 93 83 191 147 23 110 57 137 131 66 138 26 78 146 125 159 150 34 177 22 129 68 168 111 74 118 77 50 174 54 47 87 140 20 178 158 133 60 33 45 93 47 8 170 59 52 56 124 20 16 150 117 24 84 46 106 151 51 158 173 113 111 196 73 15 133 136 71 100 10 85 182 110 143 114 92 185 42 42 118 156 20 135 173 156 96 180 37 73 134 156 182 150 196 192 45 172 17 167 91 168 68 89 134 120 190 173 34 141 37 152 111 117 103 61 7 34 62 67 191 190 8 87 21 195 139 86 44 76 66 55 186 23 31 87 183 5 155 122 191 68 53 149 136 35 115 26 121 131 102 123 3 42 197 133 179 56 84 165 136 190 130 49 157 80 101 103 97 197 11 19 118 1 5 119 137 9 104 193 141 116 122 72 38 7 70 47 44 155 43 16 107 125 40 127 193 105 131 145 108 185 6 50 141 1 167 127 153 45 53 192 121 12 79 84 129 151 15 166 196 156 60 188 53 109 83 148 162 46 146 6 136 111 160 88 38 169 85 63 87 97 35 194 3 82 52 13 132 43 59 92 109 4 178 3 118 37 195 96 94 60 112 15 47 166 110 179 99 69 149 100 43 138 69 70 123 89 12 158 54 90 72 117 182 31 166 153 164 76 33 2 101 63 44 112 58 39 143 74 32 107 89 55 143 31 47 123 125 4 135 18 141 80 137 88 81 154 187 ^ 406 0 23 134 103 49 99 44 64 160 68 190 114 105 91 86 22 27 15 74 8 22 151 79 199 84 85 90 128 9 5 175 129 17 40 59 125 187 194 144 151 3 60 6 158 153 67 58 18 99 19 53 129 90 179 134 52 124 55 95 138 82 170 167 69 122 13 108 160 119 115 161 51 14 167 120 47 60 57 86 16 184 96 197 42 98 112 165 154 199 157 21 168 52 146 66 126 119 93 150 20 36 153 140 194 93 26 156 114 80 80 55 44 13 35 24 44 191 24 190 63 177 44 140 99 146 117 54 163 42 76 101 134 176 185 177 168 1 21 19 180 193 12 52 197 191 173 65 19 31 118 59 1 123 72 71 88 64 11 193 37 63 28 169 184 45 72 195 152 186 87 56 176 112 41 93 77 84 158 29 3 136 142 36 80 4 119 166 86 98 163 93 1 145 83 102 66 75 191 46 4 94 155 55 120 149 113 148 181 49 175 180 142 87 5 51 65 92 167 196 186 138 184 23 61 164 171 175 107 6 9 81 114 7 141 177 117 76 174 73 54 112 114 29 152 11 98 87 154 123 21 146 41 115 88 115 139 40 183 189 109 67 7 90 52 73 127 51 192 156 89 69 49 77 33 33 182 57 10 64 138 57 159 136 91 111 33 58 193 88 188 75 118 110 126 170 18 197 169 162 34 41 17 138 6 34 92 145 185 155 157 170 43 8 140 48 21 70 105 40 161 178 78 89 196 110 199 106 96 121 106 23 185 28 96 48 167 145 58 91 35 97 180 66 151 130 124 128 34 16 6 107 28 20 112 92 18 121 30 84 107 101 159 187 19 155 182 181 74 186 11 120 98 185 104 32 126 94 82 119 42 25 173 90 30 62 96 70 178 176 39 102 15 150 147 100 78 16 57 35 75 169 35 170 116 144 75 146 ^ 409 1 185 70 12 95 110 71 133 183 52 136 148 144 114 186 17 25 144 164 5 79 178 172 124 117 19 43 20 93 174 36 125 117 151 109 3 164 55 101 37 122 152 77 131 168 88 162 161 93 142 14 63 167 141 149 94 39 190 50 68 47 135 198 16 110 153 177 104 173 192 68 147 179 119 137 166 73 180 169 88 91 24 76 10 80 146 79 128 150 62 149 194 83 111 171 124 170 156 60 152 27 109 106 120 134 201 184 202 149 12 198 66 132 12 127 132 133 83 8 12 45 88 9 183 155 92 24 23 76 63 14 163 8 62 67 150 162 8 115 1 167 91 127 32 89 162 90 159 125 85 129 47 53 154 95 7 115 54 101 108 56 169 6 47 103 176 157 160 125 14 10 30 124 17 178 122 102 55 69 15 60 202 49 171 74 148 94 92 124 67 200 184 70 83 29 127 67 100 140 131 165 176 4 182 2 167 20 193 33 160 43 173 71 112 68 97 157 57 169 138 113 86 44 38 40 55 19 196 201 31 21 8 165 23 26 41 155 195 183 102 158 25 94 142 146 129 150 9 30 177 154 195 51 36 175 139 28 59 31 124 167 41 105 173 121 134 130 65 185 17 78 78 181 137 13 95 57 137 116 51 118 16 78 131 115 154 145 29 177 22 129 68 168 91 74 98 72 30 174 39 37 72 130 15 163 158 128 50 18 25 73 27 191 150 59 52 36 104 20 11 130 97 4 79 46 106 141 46 138 163 108 106 191 68 15 113 136 66 100 193 65 182 105 123 99 72 180 37 22 108 156 10 130 168 141 96 160 22 58 134 151 162 140 181 187 35 157 7 147 76 163 58 84 129 100 190 153 24 126 32 142 96 107 88 41 2 14 42 52 186 170 3 82 11 180 119 66 29 56 66 50 171 3 11 77 163 5 150 112 128 ^ 413 1 47 25 135 129 7 108 19 107 117 102 102 3 28 190 112 165 56 63 165 122 183 116 28 157 52 73 89 90 169 202 12 111 185 203 91 116 200 97 193 134 116 122 44 31 7 63 26 37 134 22 2 93 125 33 99 186 77 124 131 94 171 183 50 113 178 146 127 153 45 32 164 121 203 58 56 108 130 192 166 168 128 39 188 53 102 69 148 141 18 139 197 108 97 132 74 24 155 71 63 59 97 21 194 180 61 45 204 132 29 31 85 88 188 164 187 118 37 167 82 94 60 98 1 47 152 110 172 85 55 128 72 43 117 41 42 116 61 12 144 40 62 58 117 168 17 159 139 164 76 5 193 101 56 30 105 30 11 143 60 32 86 68 41 136 31 40 123 118 181 135 195 127 59 130 81 53 147 62 13 124 98 34 79 39 49 145 53 180 94 105 91 71 2 27 5 54 193 7 141 79 199 84 75 70 128 199 195 160 119 17 20 54 115 187 184 129 146 193 40 201 143 138 57 43 18 94 204 38 114 80 179 114 47 119 50 80 118 82 160 152 49 112 198 88 155 104 95 151 36 199 162 100 27 50 47 86 195 16 179 81 192 27 83 107 150 134 194 147 1 158 32 131 61 111 119 83 140 5 21 133 120 174 78 26 136 109 65 80 40 29 203 25 24 44 191 14 170 43 162 34 140 99 141 112 54 148 42 71 96 119 161 165 167 148 186 11 4 180 188 197 42 182 181 168 50 14 26 103 49 1 113 67 61 78 59 196 173 32 53 8 154 169 30 72 175 152 176 87 36 166 102 36 88 77 79 138 24 188 131 127 26 70 194 114 146 66 93 158 93 191 125 78 92 51 60 176 26 4 74 135 35 120 129 113 133 181 29 170 170 137 77 190 46 45 77 157 191 186 138 184 18 61 144 151 175 107 6 194 81 114 2 126 110 ^ 427 1 85 60 150 73 38 88 90 5 128 11 98 55 130 91 13 146 9 91 88 107 139 16 159 189 93 35 191 66 28 65 95 51 184 148 57 45 49 61 25 9 166 49 194 64 130 33 143 112 67 111 1 58 177 80 164 59 110 94 118 170 194 197 169 154 10 41 193 114 190 26 92 145 177 155 125 146 35 200 124 48 21 46 89 40 153 178 62 65 196 86 175 90 80 89 98 23 169 4 88 32 135 137 26 75 11 81 172 34 151 130 108 104 34 200 182 83 12 196 112 84 202 97 206 60 75 69 159 163 19 131 174 157 66 178 195 104 66 161 104 8 126 70 66 103 26 17 141 90 22 54 64 38 146 168 39 70 199 142 147 92 70 8 25 35 75 161 3 138 92 128 43 59 185 55 205 95 100 71 123 173 42 126 128 144 94 176 205 20 139 149 198 59 168 172 109 112 9 33 10 73 154 36 115 97 131 99 196 144 45 81 22 112 142 72 131 148 83 162 161 78 142 14 53 157 141 139 74 29 180 35 58 27 115 198 1 90 138 167 89 173 192 48 137 159 114 132 156 58 160 154 68 76 19 56 5 70 141 64 113 150 47 129 184 73 96 166 124 155 151 55 147 17 109 86 100 129 201 164 192 149 7 193 56 112 200 107 122 133 63 206 2 40 78 9 183 140 82 4 13 71 48 4 163 201 57 62 140 157 8 100 204 162 86 117 12 89 147 75 144 120 85 109 37 48 154 85 2 115 39 96 108 46 164 1 32 103 176 147 150 105 207 10 15 119 2 173 117 87 50 69 50 202 39 171 69 133 89 72 114 57 195 179 70 83 29 122 67 85 135 111 160 171 202 172 2 147 183 33 160 38 163 51 92 53 82 137 52 149 123 98 81 39 38 30 55 14 186 196 11 6 3 155 18 16 26 150 180 168 97 148 25 84 127 136 119 135 4 30 162 144 195 46 31 170 119 28 190 ^ 443 1 17 96 167 27 91 152 100 106 109 65 164 10 57 71 167 123 209 74 57 137 95 30 90 2 78 110 101 147 138 22 177 22 129 68 168 63 74 70 65 2 174 18 23 51 116 8 142 158 121 36 207 207 45 209 170 122 59 52 8 76 20 4 102 69 186 72 46 106 127 39 110 149 101 99 184 61 15 85 136 59 100 172 37 182 98 95 78 44 173 30 204 94 156 206 123 161 120 96 132 1 37 134 144 134 126 160 180 21 136 203 119 55 156 44 77 122 72 190 125 10 105 25 128 75 93 67 13 205 196 14 31 179 142 206 75 207 159 91 38 8 28 66 43 150 185 193 63 135 5 143 98 143 32 5 125 124 197 103 14 97 107 102 87 3 18 185 97 155 56 48 165 112 178 106 13 157 32 53 79 85 149 197 7 106 175 203 71 101 195 92 193 129 116 122 24 26 7 58 11 32 119 7 202 83 125 28 79 181 57 119 121 84 161 168 50 93 163 131 127 153 45 17 144 121 198 43 36 93 115 177 166 148 108 24 188 53 97 59 148 126 208 134 192 88 87 112 64 14 145 61 63 39 97 11 194 165 46 40 199 132 19 11 80 73 178 154 177 118 37 147 72 94 60 88 201 47 142 110 167 75 45 113 52 43 102 21 22 111 41 12 134 30 42 48 117 158 7 154 129 164 76 195 188 101 51 20 100 10 201 143 50 32 71 53 31 131 31 35 123 113 166 135 180 117 44 125 76 33 142 62 3 114 93 19 59 34 34 130 38 170 74 105 91 56 192 27 205 34 178 202 131 79 199 84 65 50 128 189 185 145 109 17 49 105 187 174 114 141 183 20 196 128 123 47 28 18 89 189 23 99 70 179 94 42 114 45 65 98 82 150 137 29 102 183 68 150 89 75 141 21 184 157 80 7 40 37 86 190 16 174 66 187 12 68 102 135 114 189 137 191 148 12 116 56 96 119 73 130 200 6 113 100 154 63 26 116 104 50 80 25 14 193 83 ^ 436 1 24 44 191 211 138 11 138 18 140 99 133 104 54 124 42 63 88 95 137 133 151 116 162 208 193 180 180 173 26 158 165 160 26 6 18 79 33 1 97 59 45 62 51 172 141 24 37 189 130 145 6 72 143 152 160 87 4 150 86 28 80 77 71 106 16 164 123 103 10 54 178 106 114 34 85 150 93 175 93 70 76 27 36 152 207 4 42 103 3 120 97 113 109 181 210 162 154 129 61 166 38 13 53 141 183 186 138 184 10 61 112 119 175 107 6 170 81 114 207 102 125 65 50 135 73 28 73 75 203 113 11 98 35 115 71 8 146 202 76 88 102 139 1 144 189 83 15 181 51 13 60 75 51 179 143 37 30 49 51 20 207 156 44 184 64 125 18 133 97 52 111 194 58 167 75 149 49 105 84 113 170 179 197 169 149 208 41 178 99 180 21 92 145 172 155 105 131 30 208 200 114 48 21 31 79 40 148 178 52 50 196 71 160 80 70 69 93 23 159 202 83 22 115 132 6 65 209 71 167 14 151 130 98 89 34 190 167 68 2 181 112 79 192 82 191 45 55 49 159 148 19 116 169 142 61 173 185 94 46 146 104 206 126 55 56 93 16 12 121 90 17 49 44 18 126 163 39 50 189 137 147 87 65 3 5 35 75 156 196 118 77 118 23 54 185 40 195 95 90 71 113 163 32 116 108 144 74 166 190 15 134 134 188 39 158 172 94 107 212 23 53 134 36 105 77 111 89 186 124 35 61 7 102 132 67 131 128 78 162 161 63 142 14 43 147 141 129 54 19 170 20 48 7 95 198 199 70 123 157 74 173 192 28 127 139 109 127 146 43 140 139 48 61 14 36 60 136 49 98 150 32 109 174 63 81 161 124 140 146 50 142 7 109 66 80 124 201 144 182 149 2 188 46 92 185 87 112 133 43 201 205 35 68 9 183 125 72 197 3 66 33 207 163 191 52 57 130 152 8 85 204 157 81 107 205 187 ^ 462 1 126 54 123 113 85 81 23 41 154 71 210 115 18 89 108 32 157 209 11 103 176 133 136 77 193 10 209 112 196 166 110 66 43 69 194 36 202 25 171 62 112 82 44 100 43 188 172 70 83 29 115 67 64 128 83 153 164 195 158 2 119 187 169 33 160 31 149 23 64 32 61 109 45 121 102 77 74 32 38 16 55 7 172 189 198 200 211 141 11 2 5 143 159 147 90 134 25 70 106 122 105 114 212 30 141 130 195 39 24 163 91 28 11 7 76 167 17 81 137 85 86 94 65 149 5 42 66 157 113 204 59 57 137 80 15 70 207 78 95 91 142 133 17 177 22 129 68 168 43 74 50 60 197 174 3 13 36 106 3 127 158 116 26 197 192 25 194 155 102 59 52 203 56 20 214 82 49 171 67 46 106 117 34 90 139 96 94 179 56 15 65 136 54 100 157 17 182 93 75 63 24 168 25 189 84 156 201 118 156 105 96 112 201 22 134 139 114 116 145 175 11 121 198 99 40 151 34 72 117 52 190 105 90 20 118 60 83 52 208 205 181 209 16 174 122 206 70 202 144 71 18 208 8 66 38 135 170 178 53 115 5 138 88 123 17 200 115 119 182 98 9 87 97 102 72 3 8 180 82 145 56 33 165 102 173 96 213 157 12 33 69 80 129 192 2 101 165 203 51 86 190 87 193 124 116 122 4 21 7 53 211 27 104 207 197 73 125 23 59 176 37 114 111 74 151 153 50 73 148 116 127 153 45 2 124 121 193 28 16 78 100 162 166 128 88 9 188 53 92 49 148 111 193 129 187 68 77 92 54 4 135 51 63 19 97 1 194 150 31 35 194 132 9 206 75 58 168 144 167 118 37 127 62 94 60 78 196 47 132 110 162 65 35 98 32 43 87 1 2 106 21 12 124 20 22 38 117 148 212 149 119 164 76 180 183 101 46 10 95 205 186 143 40 32 56 38 21 126 31 30 123 108 151 135 165 107 29 120 71 13 137 62 208 104 88 4 39 29 19 115 23 160 54 105 91 41 177 27 200 14 163 124 ^ 453 0 115 79 199 84 49 18 128 173 169 121 93 17 186 41 89 187 158 90 133 167 206 188 104 99 31 4 18 81 165 217 75 54 179 62 34 106 37 41 66 82 134 113 215 86 159 36 142 65 43 125 215 160 149 48 193 24 21 86 182 16 166 42 179 206 44 94 111 82 181 121 167 132 198 92 48 72 119 57 114 184 200 81 68 122 39 26 84 96 26 80 1 208 177 217 24 44 191 206 118 209 123 8 140 99 128 99 54 109 42 58 83 80 122 113 141 96 147 203 183 180 175 158 16 143 155 155 11 1 13 64 23 1 87 54 35 52 46 157 121 19 27 174 115 130 209 72 123 152 150 87 202 140 76 23 75 77 66 86 11 149 118 88 44 168 101 94 14 80 145 93 165 73 65 66 12 21 137 192 4 22 83 201 120 77 113 94 181 195 157 144 124 51 151 33 211 38 131 178 186 138 184 5 61 92 99 175 107 6 155 81 114 207 87 105 45 40 120 73 18 58 60 193 98 11 98 15 100 51 3 146 187 61 88 97 139 204 129 189 73 213 171 36 216 55 55 51 174 138 17 15 49 41 15 197 146 39 174 64 120 3 123 82 37 111 179 58 157 70 134 39 100 74 108 170 164 197 169 144 198 41 163 84 170 16 92 145 167 155 85 116 25 208 200 104 48 21 16 69 40 143 178 42 35 196 56 145 70 60 49 88 23 149 192 78 12 95 127 204 55 199 61 162 212 151 130 88 74 34 180 152 53 210 166 112 74 182 67 176 30 35 29 159 133 19 101 164 127 56 168 175 84 26 131 104 196 126 40 46 83 6 7 101 90 12 44 24 216 106 158 39 30 179 132 147 82 60 216 203 35 75 151 181 98 62 108 3 49 185 25 185 95 80 71 103 153 22 106 88 144 54 156 175 10 129 119 178 19 148 172 79 102 207 13 208 33 114 36 95 57 91 79 176 104 25 41 210 92 122 62 131 108 73 162 161 48 142 14 33 137 141 119 34 9 160 5 38 205 75 198 189 50 108 112 ^ 454 1 53 173 192 113 111 102 120 132 22 112 118 20 40 7 8 213 46 129 28 77 150 11 81 160 49 60 154 124 119 139 43 135 213 109 38 52 117 201 116 168 149 215 181 32 64 164 59 98 133 15 194 198 28 54 9 183 104 58 176 209 59 12 200 163 177 45 50 116 145 8 64 204 150 74 93 184 89 111 39 108 108 85 61 13 36 154 61 210 115 3 84 108 22 152 209 216 103 176 123 126 57 183 10 199 107 186 161 105 51 38 69 184 26 202 15 171 57 97 77 24 90 33 183 167 70 83 29 110 67 49 123 63 148 159 190 148 2 99 172 159 33 160 26 139 3 44 17 46 89 40 101 87 62 69 27 38 6 55 2 162 184 183 190 211 131 6 212 210 138 144 132 85 124 25 60 91 112 95 99 212 30 126 120 195 34 19 158 71 28 211 217 56 167 7 71 122 70 66 79 65 134 27 61 147 103 199 44 57 137 65 50 202 78 80 81 137 128 12 177 22 129 68 168 23 74 30 55 182 174 208 3 21 96 218 112 158 111 16 187 177 5 179 140 82 59 52 188 36 20 214 62 29 156 62 46 106 107 29 70 129 91 89 174 51 15 45 136 49 100 142 217 182 88 55 48 4 163 20 174 74 156 196 113 151 90 96 92 191 7 134 134 94 106 130 170 1 106 193 79 25 146 24 67 112 32 190 85 210 75 15 108 45 73 37 193 205 166 194 1 169 102 206 65 197 129 51 218 198 208 66 33 120 155 163 43 95 5 133 78 103 2 185 105 114 167 93 4 77 87 102 57 3 218 175 67 135 56 18 165 92 168 86 203 157 212 13 59 75 109 187 217 96 155 203 31 71 185 82 193 119 116 122 204 16 7 48 201 22 89 197 192 63 125 18 39 171 17 109 101 64 141 138 50 53 133 101 127 153 45 207 104 121 188 13 216 63 85 147 166 108 68 214 188 53 87 39 148 96 178 124 182 48 67 72 44 214 125 41 63 219 97 211 194 135 16 30 189 132 219 191 70 43 158 181 ^ 475 0 153 118 37 99 48 94 60 64 189 47 118 110 155 51 21 77 4 43 66 195 196 99 215 12 110 6 216 24 117 134 205 142 105 164 76 159 176 101 39 218 88 184 165 143 26 32 35 17 7 119 31 23 123 101 130 135 144 93 8 113 64 207 130 62 201 90 81 205 11 22 220 94 2 146 26 105 91 20 156 27 193 208 142 178 107 79 199 84 41 2 128 165 161 109 85 17 174 37 81 187 150 78 129 159 194 184 92 87 23 214 18 77 153 209 63 46 179 46 30 102 33 29 50 82 126 101 203 78 147 20 138 53 27 117 207 148 145 32 181 16 13 86 178 16 162 30 175 198 32 90 99 66 177 113 155 124 186 80 44 60 119 49 106 176 192 65 52 106 27 26 68 92 14 80 211 200 169 213 24 44 191 202 102 197 111 140 99 124 95 54 97 42 54 79 68 110 97 133 80 135 199 175 180 171 146 8 131 147 151 221 219 9 52 15 1 79 50 27 44 42 145 105 15 19 162 103 118 201 72 107 152 142 87 190 132 68 19 71 77 62 70 7 137 114 76 214 36 160 97 78 220 76 141 93 157 57 61 58 9 125 180 4 6 67 189 120 61 113 82 181 183 153 136 120 43 139 29 199 26 123 174 186 138 184 1 61 76 83 175 107 6 143 81 114 207 75 89 29 32 108 73 10 46 48 185 86 11 98 221 88 35 221 146 175 49 88 93 139 196 117 189 65 201 163 24 208 51 39 51 170 134 1 3 49 33 11 189 138 35 166 64 116 213 115 70 25 111 167 58 149 66 122 31 96 66 104 170 152 197 169 140 190 41 151 72 162 12 92 145 163 155 69 104 21 208 200 96 48 21 4 61 40 139 178 34 23 196 44 133 62 52 33 84 23 141 184 74 4 79 123 192 47 191 53 158 200 151 130 80 62 34 172 140 41 206 154 112 70 174 55 164 18 19 13 159 121 19 89 160 115 52 164 167 76 10 119 104 188 126 28 38 75 220 3 85 90 8 40 8 204 90 154 39 14 171 128 147 78 56 216 191 35 75 147 169 82 50 100 209 45 185 13 177 95 150 ^ 471 0 71 89 139 8 92 60 144 26 142 154 3 122 98 164 216 134 172 58 95 200 224 201 5 86 36 81 29 63 65 162 76 11 13 196 78 108 55 131 80 66 162 161 27 142 14 19 123 141 105 6 220 146 209 24 184 47 198 175 22 87 133 38 173 192 205 103 91 97 115 122 7 92 103 25 2 213 213 36 124 13 62 150 221 61 150 39 45 149 124 104 134 38 130 208 109 18 32 112 201 96 158 149 215 176 22 44 149 39 88 133 220 189 193 23 44 9 183 89 48 161 204 54 222 195 163 167 40 45 106 140 8 49 204 145 69 83 169 89 96 24 93 103 85 41 3 31 154 51 210 115 213 79 108 12 147 209 206 103 176 113 116 37 173 10 189 102 176 156 100 36 33 69 174 16 202 5 171 52 82 72 4 80 23 178 162 70 83 29 105 67 34 118 43 143 154 185 138 2 79 157 149 33 160 21 129 208 24 2 31 69 35 81 72 47 64 22 38 221 55 222 152 179 168 180 211 121 1 207 200 133 129 117 80 114 25 50 76 102 85 84 212 30 111 110 195 29 14 153 51 28 196 212 36 167 222 61 107 55 46 64 65 119 220 12 56 137 93 194 29 57 137 50 210 30 197 78 65 71 132 123 7 177 22 129 68 168 3 74 10 50 167 174 198 218 6 86 218 97 158 106 6 177 162 210 164 125 62 59 52 173 16 20 214 42 9 141 57 46 106 97 24 50 119 86 84 169 46 15 25 136 44 100 127 202 182 83 35 33 209 158 15 159 64 156 191 108 146 75 96 72 181 217 134 129 74 96 115 165 216 91 188 59 10 141 14 62 107 12 190 65 205 60 10 98 30 63 22 178 205 151 179 211 164 82 206 60 192 114 31 203 188 193 66 28 105 140 148 33 75 5 128 68 83 212 170 95 109 152 88 224 67 77 102 42 3 213 170 52 125 56 3 165 82 163 76 193 157 197 218 49 70 89 182 217 91 145 203 11 56 180 77 193 114 116 122 189 11 7 43 191 17 74 187 187 53 125 13 19 166 222 104 91 54 131 123 50 33 118 86 127 167 ^ 480 1 45 193 76 121 181 219 195 42 64 126 166 80 40 200 188 53 80 25 148 75 157 117 175 20 53 44 30 207 111 27 63 198 97 204 194 114 222 23 182 132 212 170 63 22 144 120 143 118 37 79 38 94 60 54 184 47 108 110 150 41 11 62 211 43 51 180 181 94 200 12 100 223 201 14 117 124 200 137 95 164 76 144 171 101 34 213 83 169 150 143 16 32 20 2 224 114 31 18 123 96 115 135 129 83 220 108 59 192 125 62 196 80 76 195 218 17 210 79 214 136 6 105 91 5 141 27 188 193 127 168 97 79 199 84 31 209 128 155 151 94 75 17 159 32 71 187 140 63 124 149 179 179 77 72 13 204 18 72 138 199 48 36 179 26 25 97 28 14 30 82 116 86 188 68 132 133 38 7 107 197 133 140 12 166 6 3 86 173 16 157 15 170 188 17 85 84 46 172 103 140 114 171 65 39 45 119 39 96 166 182 45 32 86 12 26 48 87 226 80 201 190 159 208 24 44 191 197 82 182 96 217 140 99 119 90 54 82 42 49 74 53 95 77 123 60 120 194 165 180 166 131 225 116 137 146 211 219 4 37 5 1 69 45 17 34 37 130 85 10 9 147 88 103 191 72 87 152 132 87 175 122 58 14 66 77 57 50 2 122 109 61 209 26 150 92 58 205 71 136 93 147 37 56 48 212 221 110 165 4 213 47 174 120 41 113 67 181 168 148 126 115 33 124 24 184 11 113 169 186 138 184 223 61 56 63 175 107 6 128 81 114 207 60 69 9 22 93 73 31 33 175 71 11 98 206 73 15 221 146 160 34 88 88 139 186 102 189 55 186 153 9 198 46 19 51 165 129 208 215 49 23 6 179 128 30 156 64 111 203 105 55 10 111 152 58 139 61 107 21 91 56 99 170 137 197 169 135 180 41 136 57 152 7 92 145 158 155 49 89 16 208 200 86 48 21 216 51 40 134 178 24 8 196 29 118 52 42 13 79 23 131 174 69 221 59 118 177 37 181 43 153 185 151 130 70 47 34 162 125 26 201 139 112 65 164 40 149 3 226 220 159 106 19 74 155 100 47 159 157 193 ^ 471 0 211 98 104 174 126 7 24 61 213 225 57 90 1 33 209 183 62 147 39 215 157 121 147 71 49 216 170 35 75 140 148 54 29 86 188 38 185 221 163 95 58 71 81 131 84 44 144 10 134 142 228 118 86 156 204 126 172 46 91 196 220 197 218 70 36 73 13 47 57 154 60 3 226 188 70 100 51 131 64 62 162 161 15 142 14 11 115 141 97 219 216 138 201 16 172 31 198 167 6 75 125 26 173 192 193 95 75 93 111 114 224 76 91 213 13 227 201 213 28 120 1 50 150 213 45 142 31 33 145 124 92 130 34 126 204 109 2 16 108 201 80 150 149 215 172 14 28 137 23 80 133 208 185 189 19 36 9 183 77 40 149 200 50 214 191 163 159 36 41 98 136 8 37 204 141 65 75 157 89 84 12 81 99 85 25 224 27 154 43 210 115 205 75 108 4 143 209 198 103 176 105 108 21 165 10 181 98 168 152 96 24 29 69 166 8 202 226 171 48 70 68 217 72 15 174 158 70 83 29 101 67 22 114 27 139 150 181 130 2 63 145 141 33 160 17 121 196 8 219 19 53 31 65 60 35 60 18 38 217 55 222 144 175 156 172 211 113 226 203 192 129 117 105 76 106 25 42 64 94 77 72 212 30 99 102 195 25 10 149 35 28 184 208 20 167 218 53 95 43 30 52 65 107 220 52 129 85 190 17 57 137 38 202 14 193 78 53 63 128 119 3 177 22 129 68 168 216 74 223 46 155 174 190 214 223 78 218 85 158 102 227 169 150 198 152 113 46 59 52 161 20 214 26 222 129 53 46 106 89 20 34 111 82 80 165 42 15 9 136 40 100 115 190 182 79 19 21 197 154 11 147 56 156 187 104 142 63 96 56 173 209 134 125 58 88 103 161 212 79 184 43 227 137 6 58 103 225 190 49 201 48 6 90 18 55 10 166 205 139 167 203 160 66 206 56 188 102 15 191 180 181 66 24 93 128 136 25 59 5 124 60 67 204 158 87 105 140 84 224 59 69 102 30 3 209 166 40 117 56 220 165 74 159 68 185 157 185 206 41 66 167 ^ 490 1 176 217 85 133 203 218 38 174 71 193 108 116 122 171 5 7 37 179 11 56 175 181 41 125 7 226 160 204 98 79 42 119 105 50 9 100 68 127 153 45 185 60 121 177 211 183 30 52 114 166 64 24 192 188 53 76 17 148 63 145 113 171 4 45 28 22 203 103 19 63 186 97 200 194 102 214 19 178 132 208 158 59 10 136 112 135 118 37 63 30 94 60 46 180 47 100 110 146 33 3 50 199 43 39 168 169 90 188 12 92 219 189 6 117 116 196 133 87 164 76 132 167 101 30 209 79 157 138 143 8 32 8 221 220 110 31 14 123 92 103 135 117 75 212 104 55 180 121 62 192 72 72 187 206 13 202 67 206 128 221 105 91 224 129 27 184 181 115 160 89 79 199 84 23 197 128 147 143 82 67 17 147 28 63 187 132 51 120 141 167 175 65 60 5 196 18 68 126 191 36 28 179 10 21 93 24 2 14 82 108 74 176 60 120 215 129 26 222 99 189 121 136 227 154 229 226 86 169 16 153 3 166 180 5 81 72 30 168 95 128 106 159 53 35 33 119 31 88 158 174 29 16 70 26 32 83 218 80 193 182 151 204 24 44 191 193 66 170 84 213 140 99 115 86 54 70 42 45 70 41 83 61 115 44 108 190 157 180 162 119 221 104 129 142 203 219 25 228 1 61 41 9 26 33 118 69 6 1 135 76 91 183 72 71 152 124 87 163 114 50 10 62 77 53 34 229 110 105 49 205 18 142 88 42 193 67 132 93 139 21 52 40 204 213 98 153 4 201 31 162 120 25 113 55 181 156 144 118 111 25 112 20 172 230 105 165 186 138 184 223 61 40 47 175 107 6 116 81 114 207 48 53 224 14 81 73 223 19 21 167 59 11 98 194 61 230 221 146 148 22 88 84 139 178 90 189 47 174 145 228 190 42 3 51 161 125 196 207 49 15 2 171 120 26 148 64 107 195 97 43 229 111 140 58 131 57 95 13 87 48 95 170 125 197 169 131 172 41 124 45 144 3 92 145 154 155 33 77 12 208 200 78 48 21 208 43 40 130 178 16 227 196 17 106 44 34 228 75 23 123 166 65 217 43 114 165 29 173 35 200 ^ 479 0 167 151 130 58 29 34 150 107 8 195 121 112 59 152 22 131 218 208 202 159 88 19 56 149 82 41 153 145 54 199 86 104 166 126 228 16 53 209 225 41 90 230 29 197 171 46 143 39 203 149 117 147 67 45 216 158 35 75 136 136 38 17 78 176 34 185 213 155 95 50 71 73 123 225 76 28 144 227 126 130 228 114 74 148 192 118 172 34 87 192 216 193 206 54 36 65 230 31 49 146 44 228 214 180 62 92 47 131 48 58 162 161 3 142 14 3 107 141 89 207 212 130 193 8 160 15 198 159 223 63 117 14 173 192 181 87 59 89 107 106 216 60 79 201 1 227 189 213 20 116 222 38 150 205 29 134 23 21 141 124 80 126 30 122 200 109 219 104 201 64 142 149 215 168 6 12 125 7 72 133 196 181 185 15 28 9 183 65 32 137 196 46 206 187 163 151 32 37 90 132 8 25 204 137 61 67 145 89 72 69 95 85 9 220 23 154 35 210 115 197 71 108 229 139 209 190 103 176 97 100 5 157 10 173 94 160 148 92 12 25 69 158 202 222 171 44 58 64 205 64 7 170 154 70 83 29 97 67 10 110 11 135 146 177 122 2 47 133 133 33 160 13 113 184 225 211 7 37 27 49 48 23 56 14 38 213 55 222 136 171 144 164 211 105 226 199 184 125 105 93 72 98 25 34 52 86 69 60 212 30 87 94 195 21 6 145 19 28 172 204 4 167 214 45 83 31 14 40 65 95 220 221 48 121 77 186 5 57 137 26 194 231 189 78 41 55 124 115 232 177 22 129 68 168 204 74 211 42 143 174 182 210 215 70 218 73 158 98 223 161 138 186 140 101 30 59 52 149 217 20 214 10 210 117 49 46 106 81 16 18 103 78 76 161 38 15 226 136 36 100 103 178 182 75 3 9 185 150 7 135 48 156 183 100 138 51 96 40 165 201 134 121 42 80 91 157 208 67 180 27 219 133 231 54 99 213 190 33 197 36 2 82 6 47 231 154 205 127 155 195 156 50 206 52 184 90 232 179 172 169 66 20 81 116 124 17 43 5 120 52 51 196 146 79 101 128 80 224 65 ^ 503 1 55 102 9 3 202 159 19 103 56 206 165 60 152 54 171 157 164 185 27 59 45 171 217 80 123 203 203 23 169 66 193 103 116 122 156 7 32 169 6 41 165 176 31 125 2 211 155 189 93 69 32 109 90 50 225 85 53 127 153 45 175 40 121 172 201 168 15 37 99 166 44 4 182 188 53 71 7 148 48 130 108 166 220 35 8 12 198 93 9 63 171 97 195 194 87 204 14 173 132 203 143 54 231 126 102 125 118 37 43 20 94 60 36 175 47 90 110 141 23 229 35 184 43 24 153 154 85 173 12 82 214 174 232 117 106 191 128 77 164 76 117 162 101 25 204 74 142 123 143 234 32 229 211 215 105 31 9 123 87 88 135 102 65 202 99 50 165 116 62 187 62 67 177 191 8 192 52 196 118 206 105 91 214 114 27 179 166 100 150 79 79 199 84 13 182 128 137 133 67 57 17 132 23 53 187 122 36 115 131 152 170 50 45 231 186 18 63 111 181 21 18 179 226 16 88 19 223 230 82 98 59 161 50 105 200 124 11 207 89 179 106 131 212 139 224 221 86 164 16 148 224 161 170 226 76 57 10 163 85 113 96 144 38 30 18 119 21 78 148 164 9 232 50 221 26 12 78 208 80 183 172 141 199 24 44 191 188 46 155 69 208 140 99 110 81 54 55 42 40 65 26 68 41 105 24 93 185 147 180 157 104 216 89 119 137 193 219 231 10 223 1 51 36 235 16 28 103 49 1 227 120 61 76 173 72 51 152 114 87 148 104 40 5 57 77 48 14 229 95 100 34 200 8 132 83 22 178 62 127 93 129 1 47 30 194 203 83 138 4 186 11 147 120 5 113 40 181 141 139 108 106 15 97 15 157 220 95 160 186 138 184 223 61 20 27 175 107 6 101 81 114 207 33 33 209 4 66 73 218 4 6 157 44 11 98 179 46 215 221 146 133 7 88 79 139 168 75 189 37 159 135 218 180 37 219 51 156 120 181 197 49 5 233 161 110 21 138 64 102 185 87 28 219 111 125 58 121 52 80 3 82 38 90 170 110 197 169 126 162 41 109 30 134 234 92 145 149 155 13 62 7 208 200 68 48 21 198 33 40 125 178 6 217 196 2 91 34 24 213 70 23 113 161 ^ 470 0 58 210 15 107 144 15 159 21 142 152 151 130 48 14 34 140 92 231 190 106 112 54 142 7 116 208 193 187 159 73 19 41 144 67 36 148 135 44 184 71 104 156 126 218 6 43 204 225 21 90 230 24 182 156 26 138 39 188 139 112 147 62 40 216 143 35 75 131 121 18 2 68 161 29 185 203 145 95 40 71 63 113 220 66 8 144 212 116 115 228 109 59 138 177 108 172 19 82 187 211 188 191 34 36 55 215 11 39 136 24 223 199 170 52 82 42 131 28 53 162 161 226 142 14 231 97 141 79 192 207 120 183 236 145 233 198 149 208 48 107 237 173 192 166 77 39 84 102 96 206 40 64 186 224 227 174 213 10 111 212 23 150 195 9 124 13 6 136 124 65 121 25 117 195 109 204 218 99 201 44 132 149 215 163 234 230 110 225 62 133 181 176 180 10 18 9 183 50 22 122 191 41 196 182 163 141 27 32 80 127 8 10 204 132 56 57 130 89 57 223 54 90 85 227 215 18 154 25 210 115 187 66 108 224 134 209 180 103 176 87 90 223 147 10 163 89 150 143 87 235 20 69 148 228 202 217 171 39 43 59 190 54 235 165 149 70 83 29 92 67 233 105 229 130 141 172 112 2 27 118 123 33 160 8 103 169 210 201 230 17 22 29 33 8 51 9 38 208 55 222 126 166 129 154 211 95 226 194 174 120 90 78 67 88 25 24 37 76 59 45 212 30 72 84 195 16 1 140 237 28 157 199 222 167 209 35 68 16 232 25 65 80 220 211 43 111 67 181 228 57 137 11 184 216 184 78 26 45 119 110 232 177 22 129 68 168 189 74 196 37 128 174 172 205 205 60 218 58 158 93 218 151 123 171 125 86 10 59 52 134 202 20 214 228 195 102 44 46 106 71 11 236 93 73 71 156 33 15 211 136 31 100 88 163 182 70 221 232 170 145 2 120 38 156 178 95 133 36 96 20 155 191 134 116 22 70 76 152 203 52 175 7 209 128 226 49 94 198 190 13 192 21 235 72 229 37 221 139 205 112 140 185 151 30 206 47 179 75 217 101 ^ 502 0 158 148 66 13 60 95 103 3 15 5 113 38 23 182 125 65 94 107 73 224 37 47 102 237 3 198 155 7 95 56 198 165 52 148 46 163 157 152 173 19 55 29 167 217 76 115 203 191 11 165 62 193 99 116 122 144 236 7 28 161 2 29 157 172 23 125 238 199 151 177 89 61 24 101 78 50 213 73 41 127 153 45 167 24 121 168 193 156 3 25 87 166 28 228 174 188 53 67 239 148 36 118 104 162 208 27 232 4 194 85 1 63 159 97 191 194 75 196 10 169 132 199 131 50 223 118 94 117 118 37 27 12 94 60 28 171 47 82 110 137 15 225 23 172 43 12 141 142 81 161 12 74 210 162 228 117 98 187 124 69 164 76 105 158 101 21 200 70 130 111 143 230 32 221 203 211 101 31 5 123 83 76 135 90 57 194 95 46 153 112 62 183 54 63 169 179 4 184 40 188 110 194 105 91 206 102 27 175 154 88 142 71 79 199 84 5 170 128 129 125 55 49 17 120 19 45 187 114 24 111 123 140 166 38 33 227 178 18 59 99 173 9 10 179 214 12 84 15 215 218 82 90 47 149 42 93 188 120 239 195 81 171 94 127 200 127 220 217 86 160 16 144 216 157 162 218 72 45 234 159 77 101 88 132 26 26 6 119 13 70 140 156 233 220 34 213 26 236 74 200 80 175 164 133 195 24 44 191 184 30 143 57 204 140 99 106 77 54 43 42 36 61 14 56 25 97 8 81 181 139 180 153 92 212 77 111 133 185 219 231 238 219 1 43 32 231 8 24 91 33 237 223 108 49 64 165 72 35 152 106 87 136 96 32 1 53 77 44 238 229 83 96 22 196 124 79 6 166 58 123 93 121 225 43 22 186 195 71 126 4 174 235 135 120 229 113 28 181 129 135 100 102 7 85 11 145 212 87 156 186 138 184 223 61 4 11 175 107 6 89 81 114 207 21 17 197 236 54 73 214 232 234 149 32 11 98 167 34 203 221 146 121 235 88 75 139 160 63 189 29 147 127 210 172 33 207 51 152 116 169 189 49 237 233 153 102 17 130 64 98 177 79 16 211 111 113 58 113 48 68 235 78 30 86 170 98 197 169 122 154 41 97 18 126 234 92 145 145 155 237 50 209 ^ 481 1 208 200 56 48 21 186 21 40 119 178 236 205 196 226 73 22 12 195 64 23 101 144 54 206 241 103 132 7 151 13 138 140 151 130 40 2 34 132 80 223 186 94 112 50 134 237 104 200 181 175 159 61 19 29 140 55 32 144 127 36 172 59 104 148 126 210 240 35 200 225 5 90 230 20 170 144 10 134 39 176 131 108 147 58 36 216 131 35 75 127 109 2 232 60 149 25 185 195 137 95 32 71 55 105 216 58 234 144 200 108 103 228 105 47 130 165 100 172 7 78 183 207 184 179 18 36 47 203 237 31 128 8 219 187 162 44 74 38 131 12 49 162 161 218 142 14 227 89 141 71 180 203 112 175 232 133 221 198 141 196 36 99 229 173 192 154 69 23 80 98 88 198 24 52 174 216 227 162 213 2 107 204 11 150 187 235 116 5 236 132 124 53 117 21 113 191 109 192 206 95 201 28 124 149 215 159 230 218 98 213 54 133 169 172 176 6 10 9 183 38 14 110 187 37 188 178 163 133 23 28 72 123 8 240 204 128 52 49 118 89 45 215 42 86 85 215 211 14 154 17 210 115 179 62 108 220 130 209 172 103 176 79 82 211 139 10 155 85 142 139 83 227 16 69 140 224 202 213 171 35 31 55 178 46 231 161 145 70 83 29 88 67 225 101 217 126 137 168 104 2 11 106 115 33 160 4 95 157 198 193 222 1 18 13 21 238 47 5 38 204 55 222 118 162 117 146 211 87 226 190 166 116 78 66 63 80 25 16 25 68 51 33 212 30 60 76 195 12 239 136 225 28 145 195 210 167 205 27 56 4 220 13 65 68 220 203 39 103 59 177 220 57 137 241 176 204 180 78 14 37 115 106 232 177 22 129 68 168 177 74 184 33 116 174 164 201 197 52 218 46 158 89 214 143 111 159 113 74 236 59 52 122 190 20 214 216 183 90 40 46 106 63 7 224 85 69 67 152 29 15 199 136 27 100 76 151 182 66 209 224 158 141 240 108 30 156 174 91 129 24 96 4 147 183 134 112 6 62 64 148 199 40 171 233 201 124 222 45 90 186 190 239 188 9 235 64 221 29 213 127 178 ^ 508 1 94 122 173 145 6 206 41 173 57 199 146 150 136 66 9 48 83 91 239 243 5 109 30 7 174 113 57 90 95 69 224 29 39 102 229 3 194 151 239 87 56 190 165 44 144 38 155 157 140 161 11 51 13 163 217 72 107 203 179 243 161 58 193 95 116 122 132 236 7 24 153 242 17 149 168 15 125 238 187 147 165 85 53 16 93 66 50 201 61 29 127 153 45 159 8 121 164 185 144 235 13 75 166 12 216 166 188 53 63 235 148 24 106 100 158 196 19 220 240 190 77 237 63 147 97 187 194 63 188 6 165 132 195 119 46 215 110 86 109 118 37 11 4 94 60 20 167 47 74 110 133 7 221 11 160 43 129 130 77 149 12 66 206 150 224 117 90 183 120 61 164 76 93 154 101 17 196 66 118 99 143 226 32 213 195 207 97 31 1 123 79 64 135 78 49 186 91 42 141 108 62 179 46 59 161 167 176 28 180 102 182 105 91 198 90 27 171 142 76 134 63 79 199 84 241 158 128 121 117 43 41 17 108 15 37 187 106 12 107 115 128 162 26 21 223 170 18 55 87 165 241 2 179 202 8 80 11 207 206 82 82 35 137 34 81 176 116 231 183 73 163 82 123 188 115 216 213 86 156 16 140 208 153 154 210 68 33 222 155 69 89 80 120 14 22 238 119 5 62 132 148 221 208 18 205 26 224 70 192 80 167 156 125 191 24 44 191 180 14 131 45 200 140 99 102 73 54 31 42 32 57 2 44 9 89 236 69 177 131 180 149 80 208 65 103 129 177 219 231 230 215 1 35 28 227 20 79 17 237 219 96 37 52 157 72 19 152 98 87 124 88 24 241 49 77 40 226 229 71 92 10 192 236 116 75 234 154 54 119 93 113 213 39 14 178 187 59 114 4 162 223 123 120 217 113 16 181 117 131 92 98 243 73 7 133 204 79 152 186 138 184 223 61 232 239 175 107 6 77 81 114 207 9 1 185 232 42 73 210 224 226 141 20 11 98 155 22 191 221 146 109 227 88 71 139 152 51 189 21 135 119 202 164 29 195 51 148 112 157 181 49 233 233 145 94 13 122 64 94 169 71 4 203 111 101 58 105 44 56 231 74 22 82 170 86 197 169 118 146 41 85 6 118 234 92 145 141 149 ^ 484 1 219 32 243 208 200 48 48 21 178 13 40 115 178 232 197 196 218 61 14 4 183 60 23 93 136 50 202 229 99 120 245 143 5 134 128 151 130 32 236 34 124 68 215 182 82 112 46 126 229 92 192 169 163 159 49 19 17 136 43 28 140 119 28 160 47 104 140 126 202 236 27 196 225 235 90 230 16 158 132 240 130 39 164 123 104 147 54 32 216 119 35 75 123 97 232 224 52 137 21 185 187 129 95 24 71 47 97 212 50 222 144 188 100 91 228 101 35 122 153 92 172 241 74 179 203 180 167 2 36 39 191 225 23 120 238 215 175 154 36 66 34 131 242 45 162 161 210 142 14 223 81 141 63 168 199 104 167 228 121 209 198 133 184 24 91 221 173 192 142 61 7 76 94 80 190 8 40 162 208 227 150 213 240 103 196 245 150 179 223 108 243 228 128 124 41 113 17 109 187 109 180 194 91 201 12 116 149 215 155 226 206 86 201 46 133 157 168 172 2 2 9 183 26 6 98 183 33 180 174 163 125 19 24 64 119 8 232 204 124 48 41 106 89 33 207 30 82 85 203 207 10 154 9 210 115 171 58 108 216 126 209 164 103 176 71 74 199 131 10 147 81 134 135 79 219 12 69 132 220 202 209 171 31 19 51 166 38 227 157 141 70 83 29 84 67 217 97 205 122 133 164 96 2 241 94 107 33 160 87 145 186 185 214 231 14 243 9 230 43 1 38 200 55 222 110 158 105 138 211 79 226 186 158 112 66 54 59 72 25 8 13 60 43 21 212 30 48 68 195 8 239 132 213 28 133 191 198 167 201 19 44 238 208 1 65 56 220 195 35 95 51 173 212 57 137 233 168 192 176 78 2 29 111 102 232 177 22 129 68 168 165 74 172 29 104 174 156 197 189 44 218 34 158 85 210 135 99 147 101 62 224 59 52 110 178 20 214 204 171 78 36 46 106 55 3 212 77 65 63 148 25 15 187 136 23 100 64 139 182 62 197 216 146 137 240 96 22 156 170 87 125 12 96 234 139 175 134 108 236 54 52 144 195 28 167 221 193 120 218 41 86 174 190 227 184 243 235 56 213 21 205 115 205 71 ^ 506 0 110 165 141 238 206 37 169 45 187 134 142 124 66 5 36 71 79 235 231 5 105 22 239 166 101 49 86 83 65 224 21 31 102 221 3 190 147 231 79 56 182 165 36 140 30 147 157 128 149 3 47 245 159 217 68 99 203 167 235 157 54 193 91 116 122 120 236 7 20 145 242 5 141 164 7 125 238 175 143 153 81 45 8 85 54 50 189 49 17 127 153 45 151 240 121 160 177 132 227 1 63 166 244 204 158 188 53 59 231 148 12 94 96 154 184 11 208 236 186 69 233 63 135 97 183 194 51 180 2 161 132 191 107 42 207 102 78 101 118 37 243 244 94 60 12 163 47 66 110 129 247 217 247 148 43 236 117 118 73 137 12 58 202 138 220 117 82 179 116 53 164 76 81 150 101 13 192 62 106 87 143 222 32 205 187 203 93 31 245 123 75 52 135 66 41 178 87 38 129 104 62 175 38 55 153 155 244 168 16 172 94 170 105 91 190 78 27 167 130 64 126 55 79 199 84 237 146 128 113 109 31 33 17 96 11 29 187 98 103 107 116 158 14 9 219 162 18 51 75 157 233 242 179 190 4 76 7 199 194 82 74 23 125 26 69 164 112 223 171 65 155 70 119 176 103 212 209 86 152 16 136 200 149 146 202 64 21 210 151 61 77 72 108 2 18 230 119 245 54 124 140 209 196 2 197 26 212 66 184 80 159 148 117 187 24 44 191 176 246 119 33 196 140 99 98 69 54 19 42 28 53 238 32 241 81 224 57 173 123 180 145 68 204 53 95 125 169 219 231 222 211 1 27 24 223 240 16 67 1 237 215 84 25 40 149 72 3 152 90 87 112 80 16 241 45 77 36 214 229 59 88 246 188 232 108 71 222 142 50 115 93 105 201 35 6 170 179 47 102 4 150 211 111 120 205 113 4 181 105 127 84 94 239 61 3 121 196 71 148 186 138 184 223 61 220 227 175 107 6 65 81 114 207 245 233 173 228 30 73 206 216 218 133 8 11 98 143 10 179 221 146 97 219 88 67 139 144 39 189 13 123 111 194 156 25 183 51 144 108 145 173 49 229 233 137 86 9 114 64 90 161 63 240 195 111 89 58 97 40 44 227 70 14 78 170 74 197 169 114 138 41 73 242 110 234 177 ^ 491 0 145 135 155 207 20 243 208 200 40 48 21 170 5 40 111 178 228 189 196 210 49 6 246 171 56 23 85 128 46 198 217 95 108 241 135 247 130 116 151 130 24 228 34 116 56 207 178 70 112 42 118 221 80 184 157 151 159 37 19 5 132 31 24 136 111 20 148 35 104 132 126 194 232 19 192 225 223 90 230 12 146 120 228 126 39 152 115 100 147 50 28 216 107 35 75 119 85 220 216 44 125 17 185 179 121 95 16 71 39 89 208 42 210 144 176 92 79 228 97 23 114 141 84 172 233 70 175 199 176 155 236 36 31 179 213 15 112 226 211 163 146 28 58 30 131 230 41 162 161 202 142 14 219 73 141 55 156 195 96 159 224 109 197 198 125 172 12 83 213 173 192 130 53 241 72 90 72 182 242 28 150 200 227 138 213 236 99 188 237 150 171 211 100 239 220 124 124 29 109 13 105 183 109 168 182 87 201 246 108 149 215 151 222 194 74 189 38 133 145 164 168 248 244 9 183 14 248 86 179 29 172 170 163 117 15 20 56 115 8 224 204 120 44 33 94 89 21 199 18 78 85 191 203 6 154 1 210 115 163 54 108 212 122 209 156 103 176 63 66 187 123 10 139 77 126 131 75 211 8 69 124 216 202 205 171 27 7 47 154 30 223 153 137 70 83 29 80 67 209 93 193 118 129 160 88 2 229 82 99 33 160 246 79 133 174 177 206 219 10 231 247 222 39 247 38 196 55 222 102 154 93 130 211 71 226 182 150 108 54 42 55 64 25 1 52 35 9 212 30 36 60 195 4 239 128 201 28 121 187 186 167 197 11 32 230 196 239 65 44 220 187 31 87 43 169 204 57 137 225 160 180 172 78 240 21 107 98 232 177 22 129 68 168 153 74 160 25 92 174 148 193 181 36 218 22 158 81 206 127 87 135 89 50 212 59 52 98 166 20 214 192 159 66 32 46 106 47 249 200 69 61 59 144 21 15 175 136 19 100 52 127 182 58 185 208 134 133 240 84 14 156 166 83 121 96 222 131 167 134 104 224 46 40 140 191 16 163 209 185 116 214 37 82 162 190 215 180 235 235 48 205 13 197 103 205 76 104 161 139 232 146 ^ 516 0 33 165 33 175 122 134 112 66 1 24 59 67 231 219 5 101 14 227 158 89 41 82 71 61 224 13 23 102 213 3 186 143 223 71 56 174 165 28 136 22 139 157 116 137 247 43 233 155 217 64 91 203 155 227 153 50 193 87 116 122 108 236 7 16 137 242 245 133 160 251 125 238 163 139 141 77 37 77 42 50 177 37 5 127 153 45 143 228 121 156 169 120 219 241 51 166 232 192 150 188 53 55 227 148 82 92 150 172 3 196 232 182 61 229 63 123 97 179 194 39 172 250 157 132 187 95 38 199 94 70 93 118 37 231 240 94 60 4 159 47 58 110 125 243 213 239 136 43 228 105 106 69 125 12 50 198 126 216 117 74 175 112 45 164 76 69 146 101 9 188 58 94 75 143 218 32 197 179 199 89 31 245 123 71 40 135 54 33 170 83 34 117 100 62 171 30 51 145 143 244 160 4 164 86 158 105 91 182 66 27 163 118 52 118 47 79 199 84 233 134 128 105 101 19 25 17 84 7 21 187 90 240 99 99 104 154 2 249 215 154 18 47 63 149 225 238 179 178 72 3 191 182 82 66 11 113 18 57 152 108 215 159 57 147 58 115 164 91 208 205 86 148 16 132 192 145 138 194 60 9 198 147 53 65 64 96 242 14 222 119 241 46 116 132 197 184 238 189 26 200 62 176 80 151 140 109 183 24 44 191 172 234 107 21 192 140 99 94 65 54 7 42 24 49 230 20 229 73 212 45 169 115 180 141 56 200 41 87 121 161 219 231 214 207 1 19 20 219 236 12 55 237 237 211 72 13 28 141 72 239 152 82 87 100 72 8 241 41 77 32 202 229 47 84 238 184 228 100 67 210 130 46 111 93 97 189 31 250 162 171 35 90 4 138 199 99 120 193 113 244 181 93 123 76 90 235 49 251 109 188 63 144 186 138 184 223 61 208 215 175 107 6 53 81 114 207 237 221 161 224 18 73 202 208 210 125 248 11 98 131 250 167 221 146 85 211 88 63 139 136 27 189 5 111 103 186 148 21 171 51 140 104 133 165 49 225 233 129 78 5 106 64 86 153 55 232 187 111 77 58 89 36 32 223 66 6 74 170 62 197 169 110 130 41 61 234 102 234 92 145 133 155 201 14 243 208 200 36 48 21 166 1 40 109 178 147 ^ 522 0 179 196 200 34 251 241 156 51 23 75 118 41 193 202 90 93 236 125 242 125 101 151 130 14 218 34 106 41 197 173 55 112 37 108 211 65 174 142 136 159 22 19 245 127 16 19 131 101 10 133 20 104 122 126 184 227 9 187 225 208 90 230 7 131 105 213 121 39 137 105 95 147 45 23 216 92 35 75 114 70 205 206 34 110 12 185 169 111 95 6 71 29 79 203 32 195 144 161 82 64 228 92 8 104 126 74 172 223 65 170 194 171 140 221 36 21 164 198 5 102 211 206 148 136 18 48 25 131 215 36 162 161 192 142 14 214 63 141 45 141 190 86 149 219 94 182 198 115 157 252 73 203 173 192 115 43 226 67 85 62 172 227 13 135 190 227 123 213 231 94 178 227 150 161 196 90 234 210 119 124 14 104 8 100 178 109 153 167 82 201 231 98 149 215 146 217 179 59 174 28 133 130 159 163 248 239 9 183 254 243 71 174 24 162 165 163 107 10 15 46 110 8 214 204 115 39 23 79 89 6 189 3 73 85 176 198 1 154 246 210 115 153 49 108 207 117 209 146 103 176 53 56 172 113 10 129 72 116 126 70 201 3 69 114 211 202 200 171 22 247 42 139 20 218 148 132 70 83 29 75 67 199 88 178 113 124 155 78 2 214 67 89 33 160 246 69 118 159 167 196 204 5 216 237 212 34 247 38 191 55 222 92 149 78 120 211 61 226 177 140 103 39 27 50 54 25 245 241 42 25 249 212 30 21 50 195 254 239 123 186 28 106 182 171 167 192 1 17 220 181 229 65 29 220 177 26 77 33 164 194 57 137 215 150 165 167 78 230 11 102 93 232 177 22 129 68 168 138 74 145 20 77 174 138 188 171 26 218 7 158 76 201 117 72 120 74 35 197 59 52 83 151 20 214 177 144 51 27 46 106 37 249 185 59 56 54 139 16 15 160 136 14 100 37 112 182 53 170 198 119 128 240 69 4 156 161 78 116 240 96 207 121 157 134 99 209 36 25 135 186 1 158 194 175 111 209 32 77 147 190 200 175 225 235 38 195 3 187 88 205 61 89 151 134 217 206 30 162 24 166 113 128 103 66 253 15 50 58 228 210 5 98 8 218 152 80 35 79 62 58 224 7 17 102 207 3 183 140 217 65 56 168 165 22 133 16 133 157 107 128 244 12 ^ 517 1 218 150 217 59 81 203 140 217 148 45 193 82 116 122 93 236 7 11 127 242 235 123 155 246 125 238 148 134 126 72 27 247 67 27 50 162 22 247 127 153 45 133 213 121 151 159 105 209 231 36 166 217 177 140 188 53 50 222 148 242 67 87 145 157 250 181 227 177 51 224 63 108 97 174 194 24 162 250 152 132 182 80 33 189 84 60 83 118 37 216 235 94 60 251 154 47 48 110 120 238 208 229 121 43 218 90 91 64 110 12 40 193 111 211 117 64 170 107 35 164 76 54 141 101 4 183 53 79 60 143 213 32 187 169 194 84 31 245 123 66 25 135 39 23 160 78 29 102 95 62 166 20 46 135 128 244 150 246 154 76 143 105 91 172 51 27 158 103 37 108 37 79 199 84 228 119 128 95 91 4 15 17 69 2 11 187 80 230 94 89 89 149 244 239 210 144 18 42 48 139 215 233 179 163 252 67 255 181 167 82 56 253 98 8 42 137 103 205 144 47 137 43 110 149 76 203 200 86 143 16 127 182 140 128 184 55 251 183 142 43 50 54 81 232 9 212 119 236 36 106 122 182 169 223 179 26 185 57 166 80 141 130 99 178 24 44 191 167 219 92 6 187 140 99 89 60 54 249 42 19 44 220 5 214 63 197 30 164 105 180 136 41 195 26 77 116 151 219 231 204 202 1 9 15 214 231 7 40 222 237 206 57 255 13 131 72 224 152 72 87 85 62 255 241 36 77 27 187 229 32 79 228 179 223 90 62 195 115 41 106 93 87 174 26 245 152 161 20 75 4 123 184 84 120 178 113 234 181 78 118 66 85 230 34 251 94 178 53 139 186 138 184 223 61 193 200 175 107 6 38 81 114 207 227 206 146 219 3 73 197 198 200 115 238 11 98 116 240 152 221 146 70 201 88 58 139 126 12 189 252 96 93 176 138 16 156 51 135 99 118 155 49 220 233 119 68 96 64 81 143 45 222 177 111 62 58 79 31 17 218 61 253 69 170 47 197 169 105 120 41 46 224 92 234 92 145 128 155 186 256 243 208 200 26 48 21 156 248 40 104 178 221 175 196 196 28 249 239 150 49 23 71 114 39 191 196 88 87 234 121 240 123 95 151 130 10 214 34 102 35 193 171 49 112 35 104 207 59 170 136 130 159 16 19 241 125 213 ^ 529 1 15 127 93 2 121 8 104 114 126 176 223 1 183 225 196 90 230 3 119 93 201 117 39 125 97 91 147 41 19 216 80 35 75 110 58 193 198 26 98 8 185 161 103 95 257 71 21 71 199 24 183 144 149 74 52 228 88 255 96 114 66 172 215 61 166 190 167 128 209 36 13 152 186 256 94 199 202 136 128 10 40 21 131 203 32 162 161 184 142 14 210 55 141 37 129 186 78 141 215 82 170 198 107 145 244 65 195 173 192 103 35 214 63 81 54 164 215 1 123 182 227 111 213 227 90 170 219 150 153 184 82 230 202 115 124 2 100 4 96 174 109 141 155 78 201 219 90 149 215 142 213 167 47 162 20 133 118 155 159 248 235 9 183 246 239 59 170 20 154 161 163 99 6 11 38 106 8 206 204 111 35 15 67 89 253 181 250 69 85 164 194 256 154 242 210 115 145 45 108 203 113 209 138 103 176 45 48 160 105 10 121 68 108 122 66 193 258 69 106 207 202 196 171 18 239 38 127 12 214 144 128 70 83 29 71 67 191 84 166 109 120 151 70 2 202 55 81 33 160 246 61 106 147 159 188 192 1 204 229 204 30 247 38 187 55 222 84 145 66 112 211 53 226 173 132 99 27 15 46 46 25 241 233 34 17 241 212 30 9 42 195 254 239 119 174 28 94 178 159 167 188 252 5 212 169 221 65 17 220 169 22 69 25 160 186 57 137 207 142 153 163 78 222 3 98 89 232 177 22 129 68 168 126 74 133 16 65 174 130 184 163 18 218 254 158 72 197 109 60 108 62 23 185 59 52 71 139 20 214 165 132 39 23 46 106 29 249 173 51 52 50 135 12 15 148 136 10 100 25 100 182 49 158 190 107 124 240 57 255 156 157 74 112 232 96 195 113 149 134 95 197 28 13 131 182 248 154 182 167 107 205 28 73 135 190 188 171 217 235 30 187 254 179 76 205 49 77 143 130 205 206 26 158 12 154 101 120 91 66 253 3 38 46 224 198 5 94 206 144 68 27 75 50 54 224 258 9 102 199 3 179 136 209 57 56 160 165 14 129 8 125 157 95 116 240 36 212 148 217 57 77 203 134 213 146 43 193 80 116 122 87 236 7 9 123 242 231 119 153 244 125 238 142 132 120 70 23 245 63 21 50 156 16 243 127 153 45 129 207 121 149 155 99 205 227 30 166 211 57 ^ 548 0 134 188 53 47 219 148 236 58 84 142 148 247 172 224 174 45 221 63 99 97 171 194 15 156 250 149 132 179 71 30 183 78 54 77 118 37 207 232 94 60 248 151 47 42 110 117 235 205 223 112 43 212 81 82 61 101 12 34 190 102 208 117 58 167 104 29 164 76 45 138 101 1 180 50 70 51 143 210 32 181 163 191 81 31 245 123 63 16 135 30 17 154 75 26 93 92 62 163 14 43 129 119 244 144 240 148 70 134 105 91 166 42 27 155 94 28 102 31 79 199 84 225 110 128 89 85 255 9 17 60 259 5 187 74 224 91 83 80 146 238 233 207 138 18 39 39 133 209 230 179 154 252 64 255 175 158 82 50 247 89 2 33 128 100 199 135 41 131 34 107 140 67 200 197 86 140 16 124 176 137 122 178 52 245 174 139 37 41 48 72 226 6 206 119 233 30 100 116 173 160 214 173 26 176 54 160 80 135 124 93 175 24 44 191 164 210 83 257 184 140 99 86 57 54 243 42 16 41 214 256 205 57 188 21 161 99 180 133 32 192 17 71 113 145 219 231 198 199 1 3 12 211 228 4 31 213 237 203 48 249 4 125 72 215 152 66 87 76 56 252 241 33 77 24 178 229 23 76 222 176 220 84 59 186 106 38 103 93 81 165 23 242 146 155 11 66 4 114 175 75 120 169 113 228 181 69 115 60 82 227 25 251 85 172 47 136 186 138 184 223 61 184 191 175 107 6 29 81 114 207 221 197 137 216 254 73 194 192 194 109 232 11 98 107 234 143 221 146 61 195 88 55 139 120 3 189 249 87 87 170 132 13 147 51 132 96 109 149 49 217 233 113 62 257 90 64 78 137 39 216 171 111 53 58 73 28 8 215 58 250 66 170 38 197 169 102 114 41 37 218 86 234 92 145 125 155 177 250 243 208 200 20 48 21 150 245 40 101 178 218 169 196 190 19 246 236 141 46 23 65 108 36 188 187 85 78 231 115 237 120 86 151 130 4 208 34 96 26 187 168 40 112 32 98 201 50 164 127 121 159 7 19 235 122 1 14 126 91 118 5 104 112 126 174 222 259 182 225 193 90 230 2 116 90 198 116 39 122 95 90 147 40 18 216 77 35 75 109 55 190 196 24 95 7 185 159 101 95 256 71 19 69 198 22 180 144 146 72 49 228 87 253 94 111 64 172 213 60 165 189 166 125 206 36 11 149 183 255 92 196 201 133 126 8 38 20 131 213 ^ 547 0 29 162 161 178 142 14 207 49 141 31 120 183 72 135 212 73 161 198 101 136 238 59 189 173 192 94 29 205 60 78 48 158 206 254 114 176 227 102 213 224 87 164 213 150 147 175 76 227 196 112 124 255 97 1 93 171 109 132 146 75 201 210 84 149 215 139 210 158 38 153 14 133 109 152 156 248 232 9 183 240 236 50 167 17 148 158 163 93 3 8 32 103 8 200 204 108 32 9 58 89 247 175 244 66 85 155 191 256 154 239 210 115 139 42 108 200 110 209 132 103 176 39 42 151 99 10 115 65 102 119 63 187 258 69 100 204 202 193 171 15 233 35 118 6 211 141 125 70 83 29 68 67 185 81 157 106 117 148 64 2 193 46 75 33 160 246 55 97 138 153 182 183 260 195 223 198 27 247 38 184 55 222 78 142 57 106 211 47 226 170 126 96 18 6 43 40 25 238 227 28 11 235 212 30 36 195 254 239 116 165 28 85 175 150 167 185 249 258 206 160 215 65 8 220 163 19 63 19 157 180 57 137 201 136 144 160 78 216 259 95 86 232 177 22 129 68 168 117 74 124 13 56 174 124 181 157 12 218 248 158 69 194 103 51 99 53 14 176 59 52 62 130 20 214 156 123 30 20 46 106 23 249 164 45 49 47 132 9 15 139 136 7 100 16 91 182 46 149 184 98 121 240 48 252 156 154 71 109 226 96 186 107 143 134 92 188 22 4 128 179 242 151 173 161 104 202 25 70 126 190 179 168 211 235 24 181 251 173 67 205 40 68 137 127 196 206 23 155 3 145 92 114 82 66 253 256 29 37 221 189 5 91 256 197 138 59 21 72 41 51 224 255 3 102 193 3 176 133 203 51 56 154 165 8 126 2 119 157 86 107 237 33 203 145 217 54 71 203 125 207 143 40 193 77 116 122 78 236 7 6 117 242 225 113 150 241 125 238 133 129 111 67 17 242 57 12 50 147 7 237 127 153 45 123 198 121 146 149 90 199 221 21 166 202 162 130 188 53 45 217 148 232 52 82 140 142 245 166 222 172 41 219 63 93 97 169 194 9 152 250 147 132 177 65 28 179 74 50 73 118 37 201 230 94 60 246 149 47 38 110 115 233 203 219 106 43 208 75 76 59 95 12 30 188 96 206 117 54 165 102 25 164 76 39 136 101 261 178 48 64 45 143 208 32 177 159 189 79 31 245 123 61 10 135 24 13 150 73 24 87 90 62 161 10 41 125 209 ^ 542 1 244 136 232 140 62 122 105 91 158 30 27 151 82 16 94 23 79 199 84 221 98 128 81 77 247 1 17 48 259 261 187 66 216 87 75 68 142 230 225 203 130 18 35 27 125 201 226 179 142 252 60 255 167 146 82 42 239 77 258 21 116 96 191 123 33 123 22 103 128 55 196 193 86 136 16 120 168 133 114 170 48 237 162 135 29 29 40 60 218 2 198 119 229 22 92 108 161 148 202 165 26 164 50 152 80 127 116 85 171 24 44 191 160 198 71 249 180 140 99 82 53 54 235 42 12 37 206 248 193 49 176 9 157 91 180 129 20 188 5 63 109 137 219 231 190 195 1 259 8 207 224 19 201 237 199 36 241 256 117 72 203 152 58 87 64 48 248 241 29 77 20 166 229 11 72 214 172 216 76 55 174 94 34 99 93 73 153 19 238 138 147 263 54 4 102 163 63 120 157 113 220 181 57 111 52 78 223 13 251 73 164 39 132 186 138 184 223 61 172 179 175 107 6 17 81 114 207 213 185 125 212 246 73 190 184 186 101 224 11 98 95 226 131 221 146 49 187 88 51 139 112 255 189 245 75 79 162 124 9 135 51 128 92 97 141 49 213 233 105 54 257 82 64 74 129 31 208 163 111 41 58 65 24 260 211 54 246 62 170 26 197 169 98 106 41 25 210 78 234 92 145 121 155 165 242 243 208 200 12 48 21 142 241 40 97 178 214 161 196 182 7 242 232 129 42 23 57 100 32 184 175 81 66 227 107 233 116 74 151 130 260 200 34 88 14 179 164 28 112 28 90 193 38 156 115 109 159 259 19 227 118 253 10 122 83 256 106 257 104 104 126 166 218 255 178 225 181 90 230 262 104 78 186 112 39 110 87 86 147 36 14 216 65 35 75 105 43 178 188 16 83 3 185 151 93 95 252 71 11 61 194 14 168 144 134 64 37 228 83 245 86 99 56 172 205 56 161 185 162 113 194 36 3 137 171 251 84 184 197 121 118 30 16 131 188 27 162 161 174 142 14 205 45 141 27 114 181 68 131 210 67 155 198 97 130 234 55 185 173 192 88 25 199 58 76 44 154 200 250 108 172 227 96 213 222 85 160 209 150 143 169 72 225 192 110 124 251 95 263 91 169 109 126 140 73 201 204 80 149 215 137 208 152 32 147 10 133 103 150 154 248 230 9 183 236 234 44 165 15 144 156 163 89 1 6 28 101 8 196 204 106 164 ^ 567 0 1 46 89 239 167 236 62 85 143 187 256 154 235 210 115 131 38 108 196 106 209 124 103 176 31 34 139 91 10 107 61 94 115 59 179 258 69 92 200 202 189 171 11 225 31 106 264 207 137 121 70 83 29 64 67 177 77 145 102 113 144 56 2 181 34 67 33 160 246 47 85 126 145 174 171 260 183 215 190 23 247 38 180 55 222 70 138 45 98 211 39 226 166 118 92 6 260 39 32 25 234 219 20 3 227 212 30 254 28 195 254 239 112 153 28 73 171 138 167 181 245 250 198 148 207 65 262 220 155 15 55 11 153 172 57 137 193 128 132 156 78 208 255 91 82 232 177 22 129 68 168 105 74 112 9 44 174 116 177 149 4 218 240 158 65 190 95 39 87 41 2 164 59 52 50 118 20 214 144 111 18 16 46 106 15 249 152 37 45 43 128 5 15 127 136 3 100 4 79 182 42 137 176 86 117 240 36 248 156 150 67 105 218 96 174 99 135 134 88 176 14 258 124 175 234 147 161 153 100 198 21 66 114 190 167 164 203 235 16 173 247 165 55 205 28 56 129 123 184 206 19 151 257 133 80 106 70 66 253 248 17 25 217 177 5 87 252 185 130 47 13 68 29 47 224 251 261 102 185 3 172 129 195 43 56 146 165 122 260 111 157 74 95 233 29 191 141 217 50 63 203 113 199 139 36 193 73 116 122 66 236 7 2 109 242 217 105 146 237 125 238 121 125 99 63 9 238 49 50 135 261 229 127 153 45 115 186 121 142 141 78 191 213 9 166 190 150 122 188 53 41 213 148 224 40 78 136 130 241 154 218 168 33 215 63 81 97 165 194 263 144 250 143 132 173 53 24 171 66 42 65 118 37 189 226 94 60 242 145 47 30 110 111 229 199 211 94 43 200 63 64 55 83 12 22 184 84 202 117 46 161 98 17 164 76 27 132 101 261 174 44 52 33 143 204 32 169 151 185 75 31 245 123 57 264 135 12 5 142 69 20 75 86 62 157 2 37 117 101 244 132 228 136 58 116 105 91 154 24 27 149 76 10 90 19 79 199 84 219 92 128 77 73 243 263 17 42 259 259 187 62 212 85 71 62 140 226 221 201 126 18 33 21 121 197 224 179 136 252 58 255 163 140 82 38 235 71 256 15 110 94 187 117 29 119 16 101 122 49 194 191 86 134 16 118 164 131 110 166 46 233 156 133 25 23 36 54 214 194 119 227 18 88 104 155 142 196 161 26 158 48 148 80 123 112 81 169 24 44 191 158 192 65 245 178 140 223 ^ 551 1 78 49 54 227 42 8 33 198 240 181 41 164 265 153 83 180 125 8 184 261 55 105 129 219 231 182 191 1 255 4 203 220 264 7 189 237 195 24 233 248 109 72 191 152 50 87 52 40 244 241 25 77 16 154 229 267 68 206 168 212 68 51 162 82 30 95 93 65 141 15 234 130 139 255 42 4 90 151 51 120 145 113 212 181 45 107 44 74 219 1 251 61 156 31 128 186 138 184 223 61 160 167 175 107 6 5 81 114 207 205 173 113 208 238 73 186 176 178 93 216 11 98 83 218 119 221 146 37 179 88 47 139 104 247 189 241 63 71 154 116 5 123 51 124 88 85 133 49 209 233 97 46 257 74 64 70 121 23 200 155 111 29 58 57 20 252 207 50 242 58 170 14 197 169 94 98 41 13 202 70 234 92 145 117 155 153 234 243 208 200 4 48 21 134 237 40 93 178 210 153 196 174 263 238 228 117 38 23 49 92 28 180 163 77 54 223 99 229 112 62 151 130 256 192 34 80 2 171 160 16 112 24 82 185 26 148 103 97 159 251 19 219 114 245 6 118 75 252 94 249 104 96 126 158 214 251 174 225 169 90 230 262 92 66 174 108 39 98 79 82 147 32 10 216 53 35 75 101 31 166 180 8 71 267 185 143 85 95 248 71 3 53 190 6 156 144 122 56 25 228 79 237 78 87 48 172 197 52 157 181 158 101 182 36 263 125 159 247 76 172 193 109 110 260 22 12 131 176 23 162 161 166 142 14 201 37 141 19 102 177 60 123 206 55 143 198 89 118 226 47 177 173 192 76 17 187 54 72 36 146 188 242 96 164 227 84 213 218 81 152 201 150 135 157 64 221 184 106 124 243 91 263 87 165 109 114 128 69 201 192 72 149 215 133 204 140 20 135 2 133 91 146 150 248 226 9 183 228 230 32 161 11 136 152 163 81 265 2 20 97 8 188 204 102 26 265 40 89 235 163 232 60 85 137 185 256 154 233 210 115 127 36 108 194 104 209 120 103 176 27 30 133 87 10 103 59 90 113 57 175 258 69 88 198 202 187 171 9 221 29 100 262 205 135 119 70 83 29 62 67 173 75 139 100 111 142 52 2 175 28 63 33 160 246 43 79 120 141 170 165 260 177 211 186 21 247 38 178 55 222 66 136 39 94 211 35 226 164 114 90 256 37 28 25 232 215 16 267 223 212 30 250 24 195 254 239 110 147 28 67 169 132 167 179 243 246 194 142 203 65 263 ^ 578 0 220 147 11 47 3 149 164 57 137 185 120 120 152 78 200 251 87 78 232 177 22 129 68 168 93 74 100 5 32 174 108 173 141 266 218 232 158 61 186 87 27 75 29 260 152 59 52 38 106 20 214 132 99 6 12 46 106 7 249 140 29 41 39 124 1 15 115 136 269 100 262 67 182 38 125 168 74 113 240 24 244 156 146 63 101 210 96 162 91 127 134 84 164 6 250 120 171 226 143 149 145 96 194 17 62 102 190 155 160 195 235 8 165 243 157 43 205 16 44 121 119 172 206 15 147 249 121 68 98 58 66 253 240 5 13 213 165 5 83 248 173 122 35 5 64 17 43 224 247 257 102 177 3 168 125 187 35 56 138 165 262 118 256 103 157 62 83 229 25 179 137 217 46 55 203 101 191 135 32 193 69 116 122 54 236 7 268 101 242 209 97 142 233 125 238 109 121 87 59 1 234 41 258 50 123 253 221 127 153 45 107 174 121 138 133 66 183 205 267 166 178 138 114 188 53 37 209 148 216 28 74 132 118 237 142 214 164 25 211 63 69 97 161 194 255 136 250 139 132 169 41 20 163 58 34 57 118 37 177 222 94 60 238 141 47 22 110 107 225 195 203 82 43 192 51 52 51 71 12 14 180 72 198 117 38 157 94 9 164 76 15 128 101 261 170 40 40 21 143 200 32 161 143 181 71 31 245 123 53 256 135 267 134 65 16 63 82 62 153 264 33 109 89 244 124 220 128 50 104 105 91 146 12 27 145 64 268 82 11 79 199 84 215 80 128 69 65 235 259 17 30 259 255 187 54 204 81 63 50 136 218 213 197 118 18 29 9 113 189 220 179 124 252 54 255 155 128 82 30 227 59 252 3 98 90 179 105 21 111 4 97 110 37 190 187 86 130 16 114 156 127 102 158 42 225 144 129 17 11 28 42 206 266 186 119 223 10 80 96 143 130 184 153 26 146 44 140 80 115 104 73 165 24 44 191 154 180 53 237 174 140 99 76 47 54 223 42 6 31 194 236 175 37 158 261 151 79 180 123 2 182 257 51 103 125 219 231 178 189 1 253 2 201 218 264 1 183 237 193 18 229 244 105 72 185 152 46 87 46 36 242 241 23 77 14 148 229 263 66 202 166 210 64 49 156 76 28 93 93 61 135 13 232 126 135 251 36 4 84 145 45 120 139 113 208 181 39 105 40 72 217 265 251 55 152 27 126 186 138 184 223 61 154 161 175 107 6 269 81 114 207 201 167 107 206 234 73 184 172 174 89 212 11 98 77 214 113 221 146 31 175 88 45 139 100 243 189 213 ^ 578 1 51 63 146 108 1 111 51 120 84 73 125 49 205 233 89 38 257 66 64 66 113 15 192 147 111 17 58 49 16 244 203 46 238 54 170 2 197 169 90 90 41 1 194 62 234 92 145 113 155 141 226 243 208 200 268 48 21 126 233 40 89 178 206 145 196 166 255 234 224 105 34 23 41 84 24 176 151 73 42 219 91 225 108 50 151 130 252 184 34 72 262 163 156 4 112 20 74 177 14 140 91 85 159 243 19 211 110 237 2 114 67 248 82 241 104 88 126 150 210 247 170 225 157 90 230 262 80 54 162 104 39 86 71 78 147 28 6 216 41 35 75 97 19 154 172 59 267 185 135 77 95 244 71 267 45 186 270 144 144 110 48 13 228 75 229 70 75 40 172 189 48 153 177 154 89 170 36 259 113 147 243 68 160 189 97 102 256 14 8 131 164 19 162 161 158 142 14 197 29 141 11 90 173 52 115 202 43 131 198 81 106 218 39 169 173 192 64 9 175 50 68 28 138 176 234 84 156 227 72 213 214 77 144 193 150 127 145 56 217 176 102 124 235 87 263 83 161 109 102 116 65 201 180 64 149 215 129 200 128 8 123 266 133 79 142 146 248 222 9 183 220 226 20 157 7 128 148 163 73 265 270 12 93 8 180 204 98 22 261 28 89 227 155 224 56 85 125 181 256 154 229 210 115 119 32 108 190 100 209 112 103 176 19 22 121 79 10 95 55 82 109 53 167 258 69 80 194 202 183 171 5 213 25 88 258 201 131 115 70 83 29 58 67 165 71 127 96 107 138 44 2 163 16 55 33 160 246 35 67 108 133 162 153 260 165 203 178 17 247 38 174 55 222 58 132 27 86 211 27 226 160 106 86 260 248 33 20 25 228 207 8 263 215 212 30 242 16 195 254 239 106 135 28 55 165 120 167 175 239 238 186 130 195 65 250 220 143 9 43 271 147 160 57 137 181 116 114 150 78 196 249 85 76 232 177 22 129 68 168 87 74 94 3 26 174 104 171 137 264 218 228 158 59 184 83 21 69 23 256 146 59 52 32 100 20 214 126 93 10 46 106 3 249 134 25 39 37 122 271 15 109 136 269 100 258 61 182 36 119 164 68 111 240 18 242 156 144 61 99 206 96 156 87 123 134 82 158 2 246 118 169 222 141 143 141 94 192 15 60 96 190 149 158 191 235 4 161 241 153 37 205 10 38 117 117 166 206 13 145 245 115 62 94 52 66 253 236 271 7 211 159 5 81 246 167 118 29 1 62 11 41 224 245 255 102 173 3 166 123 183 31 56 134 165 260 116 254 81 ^ 583 1 157 50 71 225 21 167 133 217 42 47 203 89 183 131 28 193 65 116 122 42 236 7 268 93 242 201 89 138 229 125 238 97 117 75 55 267 230 33 250 50 111 245 213 127 153 45 99 162 121 134 125 54 175 197 259 166 166 126 106 188 53 33 205 148 208 16 70 128 106 233 130 210 160 17 207 63 57 97 157 194 247 128 250 135 132 165 29 16 155 50 26 49 118 37 165 218 94 60 234 137 47 14 110 103 221 191 195 70 43 184 39 40 47 59 12 6 176 60 194 117 30 153 90 1 164 76 3 124 101 261 166 36 28 9 143 196 32 153 135 177 67 31 245 123 49 248 135 262 263 126 61 12 51 78 62 149 260 29 101 77 244 116 212 120 42 92 105 91 138 27 141 52 260 74 3 79 199 84 211 68 128 61 57 227 255 17 18 259 251 187 46 196 77 55 38 132 210 205 193 110 18 25 271 105 181 216 179 112 252 50 255 147 116 82 22 219 47 248 265 86 86 171 93 13 103 266 93 98 25 186 183 86 126 16 110 148 123 94 150 38 217 132 125 9 273 20 30 198 266 178 119 219 2 72 88 131 118 172 145 26 134 40 132 80 107 96 65 161 24 44 191 150 168 41 229 170 140 99 72 43 54 215 42 2 27 186 228 163 29 146 253 147 71 180 119 264 178 249 43 99 117 219 231 170 185 1 249 272 197 214 264 263 171 237 189 6 221 236 97 72 173 152 38 87 34 28 238 241 19 77 10 136 229 255 62 194 162 206 56 45 144 64 24 89 93 53 123 9 228 118 127 243 24 4 72 133 33 120 127 113 200 181 27 101 32 68 213 257 251 43 144 19 122 186 138 184 223 61 142 149 175 107 6 261 81 114 207 193 155 95 202 226 73 180 164 166 81 204 11 98 65 206 101 221 146 19 167 88 41 139 92 235 189 235 45 59 142 104 273 105 51 118 82 67 121 49 203 233 85 34 257 62 64 64 109 11 188 143 111 11 58 45 14 240 201 44 236 52 170 270 197 169 88 86 41 269 190 58 234 92 145 111 155 135 222 243 208 200 266 48 21 122 231 40 87 178 204 141 196 162 251 232 222 99 32 23 37 80 22 174 145 71 36 217 87 223 106 44 151 130 250 180 34 68 258 159 154 272 112 18 70 173 8 136 85 79 159 239 19 207 108 233 112 63 246 76 237 104 84 126 146 208 245 168 225 151 90 230 262 74 48 156 102 39 80 67 76 147 26 4 216 35 35 75 95 13 148 168 270 53 267 185 131 73 95 242 71 265 41 184 268 138 144 104 44 7 228 73 225 66 69 36 272 ^ 588 0 181 44 149 173 150 77 158 36 255 101 135 239 60 148 185 85 94 252 6 4 131 152 15 162 161 150 142 14 193 21 141 3 78 169 44 107 198 31 119 198 73 94 210 31 161 173 192 52 1 163 46 64 20 130 164 226 72 148 227 60 213 210 73 136 185 150 119 133 48 213 168 98 124 227 83 263 79 157 109 90 104 61 201 168 56 149 215 125 196 116 272 111 262 133 67 138 142 248 218 9 183 212 222 8 153 3 120 144 163 65 265 270 4 89 8 172 204 94 18 257 16 89 219 147 216 52 85 113 177 256 154 225 210 115 111 28 108 186 96 209 104 103 176 11 14 109 71 10 87 51 74 105 49 159 258 69 72 190 202 179 171 1 205 21 76 254 197 127 111 70 83 29 54 67 157 67 115 92 103 134 36 2 151 4 47 33 160 246 27 55 96 125 154 141 260 153 195 170 13 247 38 170 55 222 50 128 15 78 211 19 226 156 98 82 252 240 29 12 25 224 199 259 207 212 30 234 8 195 254 239 102 123 28 43 161 108 167 171 235 230 178 118 187 65 242 220 135 5 35 267 143 152 57 137 173 108 102 146 78 188 245 81 72 232 177 22 129 68 168 75 74 82 275 14 174 96 167 129 260 218 220 158 55 180 75 9 57 11 248 134 59 52 20 88 20 214 114 81 264 6 46 106 271 249 122 17 35 33 118 271 15 97 136 269 100 250 49 182 32 107 156 56 107 240 6 238 156 140 57 95 198 96 144 79 115 134 78 146 270 238 114 165 214 137 131 133 90 188 11 56 84 190 137 154 183 235 272 153 237 145 25 205 274 26 109 113 154 206 9 141 237 103 50 86 40 66 253 228 263 271 207 147 5 77 242 155 110 17 269 58 275 37 224 241 251 102 165 3 162 119 175 23 56 126 165 256 112 250 91 157 44 65 223 19 161 131 217 40 43 203 83 179 129 26 193 63 116 122 36 236 7 268 89 242 197 85 136 227 125 238 91 115 69 53 265 228 29 246 50 105 241 209 127 153 45 95 156 121 132 121 48 171 193 255 166 160 120 102 188 53 31 203 148 204 10 68 126 100 231 124 208 158 13 205 63 51 97 155 194 243 124 250 133 132 163 23 14 151 46 22 45 118 37 159 216 94 60 232 135 47 10 110 101 219 189 191 64 43 180 33 34 45 53 12 2 174 54 192 117 26 151 88 273 164 76 273 122 101 261 164 34 22 3 143 194 32 149 131 175 65 31 245 123 47 244 135 258 261 122 59 10 45 76 62 147 258 27 97 71 244 112 208 116 38 86 105 91 134 270 27 139 46 256 70 275 79 199 160 ^ 594 0 207 56 128 53 49 219 251 17 6 259 247 187 38 188 73 47 26 128 202 197 189 102 18 21 263 97 173 212 179 100 252 46 255 139 104 82 14 211 35 244 257 74 82 163 81 5 95 258 89 86 13 182 179 86 122 16 106 140 119 86 142 34 209 120 121 1 265 12 18 190 266 170 119 215 272 64 80 119 106 160 137 26 122 36 124 80 99 88 57 157 24 44 191 146 156 29 221 166 140 99 68 39 54 207 42 276 23 178 220 151 21 134 245 143 63 180 115 256 174 241 35 95 109 219 231 162 181 1 245 272 193 210 264 255 159 237 185 272 213 228 89 72 161 152 30 87 22 20 234 241 15 77 6 124 229 247 58 186 158 202 48 41 132 52 20 85 93 45 111 5 224 110 119 235 12 4 60 121 21 120 115 113 192 181 15 97 24 64 209 249 251 31 136 11 118 186 138 184 223 61 130 137 175 107 6 253 81 114 207 185 143 83 198 218 73 176 156 158 73 196 11 98 53 198 89 221 146 7 159 88 37 139 84 227 189 231 33 51 134 96 273 93 51 114 78 55 113 49 199 233 77 26 257 54 64 60 101 3 180 135 111 277 58 37 10 232 197 40 232 48 170 262 197 169 84 78 41 261 182 50 234 92 145 107 155 123 214 243 208 200 262 48 21 114 227 40 83 178 200 133 196 154 243 228 218 87 28 23 29 72 18 170 133 67 24 213 79 219 102 32 151 130 246 172 34 60 250 151 150 264 112 14 62 165 274 128 73 67 159 231 19 199 104 225 274 108 55 242 64 229 104 76 126 138 204 241 164 225 139 90 230 262 62 36 144 98 39 68 59 72 147 22 216 23 35 75 91 1 136 160 266 41 267 185 123 65 95 238 71 261 33 180 264 126 144 92 36 273 228 69 217 58 57 28 172 177 42 147 171 148 71 152 36 253 95 129 237 56 142 183 79 90 250 2 2 131 146 13 162 161 146 142 14 191 17 141 277 72 167 40 103 196 25 113 198 69 88 206 27 157 173 192 46 275 157 44 62 16 126 158 222 66 144 227 54 213 208 71 132 181 150 115 127 44 211 164 96 124 223 81 263 77 155 109 84 98 59 201 162 52 149 215 123 194 110 268 105 260 133 61 136 140 248 216 9 183 208 220 2 151 1 116 142 163 61 265 270 87 8 168 204 92 16 255 10 89 215 143 212 50 85 107 175 256 154 223 210 115 107 26 108 184 94 209 100 103 176 7 10 103 67 10 83 49 70 103 47 155 258 69 68 188 202 177 171 277 201 19 70 252 195 125 109 70 83 29 52 67 153 65 109 90 101 132 32 2 145 276 43 33 160 246 23 259 ^ 600 1 87 119 148 132 260 144 189 164 10 247 38 167 55 222 44 125 6 72 211 13 226 153 92 79 246 234 26 6 25 221 193 273 256 201 212 30 228 2 195 254 239 99 114 28 34 158 99 167 168 232 224 172 109 181 65 236 220 129 2 29 264 140 146 57 137 167 102 93 143 78 182 242 78 69 232 177 22 129 68 168 66 74 73 275 5 174 90 164 123 257 218 214 158 52 177 69 48 2 242 125 59 52 11 79 20 214 105 72 258 3 46 106 268 249 113 11 32 30 115 271 15 88 136 269 100 244 40 182 29 98 150 47 104 240 276 235 156 137 54 92 192 96 135 73 109 134 75 137 267 232 111 162 208 134 122 127 87 185 8 53 75 190 128 151 177 235 269 147 234 139 16 205 268 17 103 110 145 206 6 138 231 94 41 80 31 66 253 222 257 265 204 138 5 74 239 146 104 8 266 55 269 34 224 238 248 102 159 3 159 116 169 17 56 120 165 253 109 247 85 157 35 56 220 16 152 128 217 37 37 203 74 173 126 23 193 60 116 122 27 236 7 268 83 242 191 79 133 224 125 238 82 112 60 50 262 225 23 240 50 96 235 203 127 153 45 89 147 121 129 115 39 165 187 249 166 151 111 96 188 53 28 200 148 198 1 65 123 91 228 115 205 155 7 202 63 42 97 152 194 237 118 250 130 132 160 14 11 145 40 16 39 118 37 150 213 94 60 229 132 47 4 110 98 216 186 185 55 43 174 24 25 42 44 12 275 171 45 189 117 20 148 85 270 164 76 267 119 101 261 161 31 13 273 143 191 32 143 125 172 62 31 245 123 44 238 135 252 258 116 56 7 36 73 62 144 255 24 91 62 244 106 202 110 32 77 105 91 128 264 27 136 37 250 64 272 79 199 84 206 53 128 51 47 217 250 17 3 259 246 187 36 186 72 45 23 127 200 195 188 100 18 20 261 95 171 211 179 97 252 45 255 137 101 82 12 209 32 243 255 71 81 161 78 3 93 256 88 83 10 181 178 86 121 16 105 138 118 84 140 33 207 117 120 278 263 10 15 188 266 168 119 214 271 62 78 116 103 157 135 26 119 35 122 80 97 86 55 156 24 44 191 145 153 26 219 165 140 99 67 38 54 205 42 276 22 176 218 148 19 131 243 142 61 180 114 254 173 239 33 94 107 219 231 160 180 1 244 272 192 209 264 253 156 237 184 270 211 226 87 72 158 152 28 87 19 18 233 241 14 77 5 121 229 245 57 184 157 201 46 40 129 49 19 84 93 43 108 4 223 108 117 233 9 4 57 118 18 120 112 113 190 181 12 96 22 63 208 247 251 28 134 9 117 186 138 184 223 61 127 216 ^ 590 1 175 107 6 247 81 114 207 179 134 74 195 212 73 173 150 152 67 190 11 98 44 192 80 221 146 279 153 88 34 139 78 221 189 228 24 45 128 90 273 84 51 111 75 46 107 49 196 233 71 20 257 48 64 57 95 278 174 129 111 271 58 31 7 226 194 37 229 45 170 256 197 169 81 72 41 255 176 44 234 92 145 104 155 114 208 243 208 200 259 48 21 108 224 40 80 178 197 127 196 148 237 225 215 78 25 23 23 66 15 167 124 64 15 210 73 216 99 23 151 130 243 166 34 54 244 145 147 258 112 11 56 159 268 122 64 58 159 225 19 193 101 219 274 105 49 239 55 223 104 70 126 132 201 238 161 225 130 90 230 262 53 27 135 95 39 59 53 69 147 19 278 216 14 35 75 88 273 127 154 263 32 267 185 117 59 95 235 71 258 27 177 261 117 144 83 30 267 228 66 211 52 48 22 172 171 39 144 168 145 62 143 36 250 86 120 234 50 133 180 70 84 247 277 280 131 137 10 162 161 140 142 14 188 11 141 274 63 164 34 97 193 16 104 198 63 79 200 21 151 173 192 37 272 148 41 59 10 120 149 216 57 138 227 45 213 205 68 126 175 150 109 118 38 208 158 93 124 217 78 263 74 152 109 75 89 56 201 153 46 149 215 120 191 101 262 96 257 133 52 133 137 248 213 9 183 202 217 274 148 279 110 139 163 55 265 270 275 84 8 162 204 89 13 252 1 89 209 137 206 47 85 98 172 256 154 220 210 115 101 23 108 181 91 209 94 103 176 1 4 94 61 10 77 46 64 100 44 149 258 69 62 185 202 174 171 277 195 16 61 249 192 122 106 70 83 29 49 67 147 62 100 87 98 129 26 2 136 270 37 33 160 246 17 40 81 115 144 126 260 138 185 160 8 247 38 165 55 222 40 123 68 211 9 226 151 88 77 242 230 24 2 25 219 189 271 254 197 212 30 224 279 195 254 239 97 108 28 28 156 93 167 166 230 220 168 103 177 65 232 220 125 25 262 138 142 57 137 163 98 87 141 78 178 240 76 67 232 177 22 129 68 168 60 74 67 275 280 174 86 162 119 255 218 210 158 50 175 65 275 42 277 238 119 59 52 5 73 20 214 99 66 254 1 46 106 266 249 107 7 30 28 113 271 15 82 136 269 100 240 34 182 27 92 146 41 102 240 272 233 156 135 52 90 188 96 129 69 105 134 73 131 265 228 109 160 204 132 116 123 85 183 6 51 69 190 122 149 173 235 267 143 232 135 10 205 264 11 99 108 139 206 4 136 227 88 35 76 25 66 253 218 253 261 202 132 5 72 237 140 203 ^ 620 0 279 262 51 261 30 224 234 244 102 151 3 155 112 161 9 56 112 165 249 105 243 77 157 23 44 216 12 140 124 217 33 29 203 62 165 122 19 193 56 116 122 15 236 7 268 75 242 183 71 129 220 125 238 70 108 48 46 258 221 15 232 50 84 227 195 127 153 45 81 135 121 125 107 27 157 179 241 166 139 99 88 188 53 24 196 148 190 272 61 119 79 224 103 201 151 282 198 63 30 97 148 194 229 110 250 126 132 156 2 7 137 32 8 31 118 37 138 209 94 60 225 128 47 279 110 94 212 182 177 43 43 166 12 13 38 32 12 271 167 33 185 117 12 144 81 266 164 76 259 115 101 261 157 27 1 265 143 187 32 135 117 168 58 31 245 123 40 230 135 244 254 108 52 3 24 69 62 140 251 20 83 50 244 98 194 102 24 65 105 91 120 256 27 132 25 242 56 268 79 199 84 202 41 128 43 39 209 246 17 274 259 242 187 28 178 68 37 11 123 192 187 184 92 18 16 253 87 163 207 179 85 252 41 255 129 89 82 4 201 20 239 247 59 77 153 66 278 85 248 84 71 281 177 174 86 117 16 101 130 114 76 132 29 199 105 116 274 255 2 3 180 266 160 119 210 267 54 70 104 91 145 127 26 107 31 114 80 89 78 47 152 24 44 191 141 141 14 211 161 140 99 63 34 54 197 42 276 18 168 210 136 11 119 235 138 53 180 110 246 169 231 25 90 99 219 231 152 176 1 240 272 188 205 264 245 144 237 180 262 203 218 79 72 146 152 20 87 7 10 229 241 10 77 1 109 229 237 53 176 153 197 38 36 117 37 15 80 93 35 96 219 100 109 225 280 4 45 106 6 120 100 113 182 181 92 14 59 204 239 251 16 126 1 113 186 138 184 223 61 115 122 175 107 6 243 81 114 207 175 128 68 193 208 73 171 146 148 63 186 11 98 38 188 74 221 146 275 149 88 32 139 74 217 189 226 18 41 124 86 273 78 51 109 73 40 103 49 194 233 67 16 257 44 64 55 91 276 170 125 111 267 58 27 5 222 192 35 227 43 170 252 197 169 79 68 41 251 172 40 234 92 145 102 155 108 204 243 208 200 257 48 21 104 222 40 78 178 195 123 196 144 233 223 213 72 23 23 19 62 13 165 118 62 9 208 69 214 97 17 151 130 241 162 34 50 240 141 145 254 112 9 52 155 264 118 58 52 159 221 19 189 99 215 274 103 45 237 49 219 104 66 126 128 199 236 159 225 124 90 230 262 47 21 129 93 39 53 49 67 147 17 278 216 8 35 75 86 269 121 150 261 26 267 185 113 55 95 233 71 256 23 175 259 111 144 77 26 263 228 64 207 48 42 18 172 167 37 142 166 143 56 137 36 248 80 114 232 46 127 257 ^ 605 1 58 76 243 273 280 131 125 6 162 161 132 142 14 184 3 141 270 51 160 26 89 189 4 92 198 55 67 192 13 143 173 192 25 268 136 37 55 2 112 137 208 45 130 227 33 213 201 64 118 167 150 101 106 30 204 150 89 124 209 74 263 70 148 109 63 77 52 201 141 38 149 215 116 187 89 254 84 253 133 40 129 133 248 209 9 183 194 213 266 144 279 102 135 163 47 265 270 271 80 8 154 204 85 9 248 274 89 201 129 198 43 85 86 168 256 154 216 210 115 93 19 108 177 87 209 86 103 176 278 281 82 53 10 69 42 56 96 40 141 258 69 54 181 202 170 171 277 187 12 49 245 188 118 102 70 83 29 45 67 139 58 88 83 94 125 18 2 124 262 29 33 160 246 9 28 69 107 136 114 260 126 177 152 4 247 38 161 55 222 32 119 273 60 211 1 226 147 80 73 234 222 20 279 25 215 181 267 250 189 212 30 216 275 195 254 239 93 96 28 16 152 81 167 162 226 212 160 91 169 65 224 220 117 281 17 258 134 134 57 137 155 90 75 137 78 170 236 72 63 232 177 22 129 68 168 48 74 55 275 272 174 78 158 111 251 218 202 158 46 171 57 267 30 269 230 107 59 52 278 61 20 214 87 54 246 282 46 106 262 249 95 284 26 24 109 271 15 70 136 269 100 232 22 182 23 80 138 29 98 240 264 229 156 131 48 86 180 96 117 61 97 134 69 119 261 220 105 156 196 128 104 115 81 179 2 47 57 190 110 145 165 235 263 135 228 127 283 205 256 284 91 104 127 206 132 219 76 23 68 13 66 253 210 245 253 198 120 5 68 233 128 92 275 260 49 257 28 224 232 242 102 147 3 153 110 157 5 56 108 165 247 103 241 73 157 17 38 214 10 134 122 217 31 25 203 56 161 120 17 193 54 116 122 9 236 7 268 71 242 179 67 127 218 125 238 64 106 42 44 256 219 11 228 50 78 223 191 127 153 45 77 129 121 123 103 21 153 175 237 166 133 93 84 188 53 22 194 148 186 268 59 117 73 222 97 199 149 280 196 63 24 97 146 194 225 106 250 124 132 154 281 5 133 28 4 27 118 37 132 207 94 60 223 126 47 277 110 92 210 180 173 37 43 162 6 7 36 26 12 269 165 27 183 117 8 142 79 264 164 76 255 113 101 261 155 25 280 261 143 185 32 131 113 166 56 31 245 123 38 226 135 240 252 104 50 1 18 67 62 138 249 18 79 44 244 94 190 98 20 59 105 91 116 252 27 130 19 238 52 266 79 199 84 200 35 128 39 35 205 244 17 270 259 240 187 24 174 66 33 5 121 188 183 182 88 18 14 249 83 159 205 179 79 252 186 ^ 615 0 255 121 77 82 283 193 8 235 239 47 73 145 54 274 77 240 80 59 273 173 170 86 113 16 97 122 110 68 124 25 191 93 112 270 247 281 278 172 266 152 119 206 263 46 62 92 79 133 119 26 95 27 106 80 81 70 39 148 24 44 191 137 129 2 203 157 140 99 59 30 54 189 42 276 14 160 202 124 3 107 227 134 45 180 106 238 165 223 17 86 91 219 231 144 172 1 236 272 184 201 264 237 132 237 176 254 195 210 71 72 134 152 12 87 282 2 225 241 6 77 284 97 229 229 49 168 149 193 30 32 105 25 11 76 93 27 84 283 215 92 101 217 272 4 33 94 281 120 88 113 174 181 275 88 6 55 200 231 251 4 118 280 109 186 138 184 223 61 103 110 175 107 6 235 81 114 207 167 116 56 189 200 73 167 138 140 55 178 11 98 26 180 62 221 146 267 141 88 28 139 66 209 189 222 6 33 116 78 273 66 51 105 69 28 95 49 190 233 59 8 257 36 64 51 83 272 162 117 111 259 58 19 1 214 188 31 223 39 170 244 197 169 75 60 41 243 164 32 234 92 145 98 155 96 196 243 208 200 253 48 21 96 218 40 74 178 191 115 196 136 225 219 209 60 19 23 11 54 9 161 106 58 284 204 61 210 93 5 151 130 237 154 34 42 232 133 141 246 112 5 44 147 256 110 46 40 159 213 19 181 95 207 274 99 37 233 37 211 104 58 126 120 195 232 155 225 112 90 230 262 35 9 117 89 39 41 41 63 147 13 278 216 283 35 75 82 261 109 142 257 14 267 185 105 47 95 229 71 252 15 171 255 99 144 65 18 255 228 60 199 40 30 10 172 159 33 138 162 139 44 125 36 244 68 102 228 38 115 174 52 72 241 271 280 131 119 4 162 161 128 142 14 182 286 141 268 45 158 22 85 187 285 86 198 51 61 188 9 139 173 192 19 266 130 35 53 285 108 131 204 39 126 227 27 213 199 62 114 163 150 97 100 26 202 146 87 124 205 72 263 68 146 109 57 71 50 201 135 34 149 215 114 185 83 250 78 251 133 34 127 131 248 207 9 183 190 211 262 142 279 98 133 163 43 265 270 269 78 8 150 204 83 7 246 270 89 197 125 194 41 85 80 166 256 154 214 210 115 89 17 108 175 85 209 82 103 176 276 279 76 49 10 65 40 52 94 38 137 258 69 50 179 202 168 171 277 183 10 43 243 186 116 100 70 83 29 43 67 135 56 82 81 92 123 14 2 118 258 25 33 160 246 5 22 63 103 132 108 260 120 173 148 2 247 38 159 55 222 28 117 269 56 211 284 226 145 76 71 230 218 18 277 25 213 177 265 248 185 212 30 212 273 195 254 239 91 90 28 10 150 75 167 160 224 175 ^ 613 0 152 79 161 65 216 220 109 281 9 254 130 126 57 137 147 82 63 133 78 162 232 68 59 232 177 22 129 68 168 36 74 43 275 264 174 70 154 103 247 218 194 158 42 167 49 259 18 261 222 95 59 52 270 49 20 214 75 42 238 282 46 106 258 249 83 280 22 20 105 271 15 58 136 269 100 224 10 182 19 68 130 17 94 240 256 225 156 127 44 82 172 96 105 53 89 134 65 107 257 212 101 152 188 124 92 107 77 175 287 43 45 190 98 141 157 235 259 127 224 119 275 205 248 276 83 100 115 206 285 128 211 64 11 60 1 66 253 202 237 245 194 108 5 64 229 116 84 267 256 45 249 24 224 228 238 102 139 3 149 106 149 286 56 100 165 243 99 237 65 157 5 26 210 6 122 118 217 27 17 203 44 153 116 13 193 50 116 122 286 236 7 268 63 242 171 59 123 214 125 238 52 102 30 40 252 215 3 220 50 66 215 183 127 153 45 69 117 121 119 95 9 145 167 229 166 121 81 76 188 53 18 190 148 178 260 55 113 61 218 85 195 145 276 192 63 12 97 142 194 217 98 250 120 132 150 273 1 125 20 285 19 118 37 120 203 94 60 219 122 47 273 110 88 206 176 165 25 43 154 283 284 32 14 12 265 161 15 179 117 138 75 260 164 76 247 109 101 261 151 21 272 253 143 181 32 123 105 162 52 31 245 123 34 218 135 232 248 96 46 286 6 63 62 134 245 14 71 32 244 86 182 90 12 47 105 91 108 244 27 126 7 230 44 262 79 199 84 196 23 128 31 27 197 240 17 262 259 236 187 16 166 62 25 282 117 180 175 178 80 18 10 241 75 151 201 179 67 252 35 255 117 71 82 281 189 2 233 235 41 71 141 48 272 73 236 78 53 269 171 168 86 111 16 95 118 108 64 120 23 187 87 110 268 243 279 274 168 266 148 119 204 261 42 58 86 73 127 115 26 89 25 102 80 77 66 35 146 24 44 191 135 123 285 199 155 140 99 57 28 54 185 42 276 12 156 198 118 288 101 223 132 41 180 104 234 163 219 13 84 87 219 231 140 170 1 234 272 182 199 264 233 126 237 174 250 191 206 67 72 128 152 8 87 278 287 223 241 4 77 284 91 229 225 47 164 147 191 26 30 99 19 9 74 93 23 78 283 213 88 97 213 268 4 27 88 277 120 82 113 170 181 271 86 2 53 198 227 251 287 114 278 107 186 138 184 223 61 97 104 175 107 6 231 81 114 207 163 110 50 187 196 73 165 134 136 51 174 11 98 20 176 56 221 146 263 137 88 26 139 62 205 189 220 29 112 74 273 60 51 103 67 22 91 49 188 233 55 4 257 32 64 49 79 270 158 113 111 255 58 15 288 210 213 ^ 624 1 28 220 36 170 238 197 169 72 54 41 237 158 26 234 92 145 95 155 87 190 243 208 200 250 48 21 90 215 40 71 178 188 109 196 130 219 216 206 51 16 23 5 48 6 158 97 55 278 201 55 207 90 286 151 130 234 148 34 36 226 127 138 240 112 2 38 141 250 104 37 31 159 207 19 175 92 201 274 96 31 230 28 205 104 52 126 114 192 229 152 225 103 90 230 262 26 108 86 39 32 35 60 147 10 278 216 277 35 75 79 255 100 136 254 5 267 185 99 41 95 226 71 249 9 168 252 90 144 56 12 249 228 57 193 34 21 4 172 153 30 135 159 136 35 116 36 241 59 93 225 32 106 171 43 66 238 268 280 131 110 1 162 161 122 142 14 179 283 141 265 36 155 16 79 184 279 77 198 45 52 182 3 133 173 192 10 263 121 32 50 282 102 122 198 30 120 227 18 213 196 59 108 157 150 91 91 20 199 140 84 124 199 69 263 65 143 109 48 62 47 201 126 28 149 215 111 182 74 244 69 248 133 25 124 128 248 204 9 183 184 208 256 139 279 92 130 163 37 265 270 266 75 8 144 204 80 4 243 264 89 191 119 188 38 85 71 163 256 154 211 210 115 83 14 108 172 82 209 76 103 176 273 276 67 43 10 59 37 46 91 35 131 258 69 44 176 202 165 171 277 177 7 34 240 183 113 97 70 83 29 40 67 129 53 73 78 89 120 8 2 109 252 19 33 160 246 289 13 54 97 126 99 260 111 167 142 289 247 38 156 55 222 22 114 263 50 211 281 226 142 70 68 224 212 15 274 25 210 171 262 245 179 212 30 206 270 195 254 239 88 81 28 1 147 66 167 157 221 202 150 76 159 65 214 220 107 281 7 253 129 124 57 137 145 80 60 132 78 160 231 67 58 232 177 22 129 68 168 33 74 40 275 262 174 68 153 101 246 218 192 158 41 166 47 257 15 259 220 92 59 52 268 46 20 214 72 39 236 282 46 106 257 249 80 279 21 19 104 271 15 55 136 269 100 222 7 182 18 65 128 14 93 240 254 224 156 126 43 81 170 96 102 51 87 134 64 104 256 210 100 151 186 123 89 105 76 174 287 42 42 190 95 140 155 235 258 125 223 117 273 205 246 274 81 99 112 206 285 127 209 61 8 58 288 66 253 200 235 243 193 105 5 63 228 113 82 265 255 44 247 23 224 227 237 102 137 3 148 105 147 285 56 98 165 242 98 236 63 157 2 23 209 5 119 117 217 26 15 203 41 151 115 12 193 49 116 122 284 236 7 268 61 242 169 57 122 213 125 238 49 101 27 39 251 214 1 218 50 63 213 181 127 153 45 67 114 121 118 93 6 143 165 227 166 118 78 74 188 53 17 189 148 176 258 54 112 58 217 82 194 144 275 191 141 ^ 628 1 3 97 139 194 211 92 250 117 132 147 267 290 119 14 282 13 118 37 111 200 94 60 216 119 47 270 110 85 203 173 159 16 43 148 277 278 29 5 12 262 158 6 176 117 286 135 72 257 164 76 241 106 101 261 148 18 266 247 143 178 32 117 99 159 49 31 245 123 31 212 135 226 245 90 43 286 289 60 62 131 242 11 65 23 244 80 176 84 6 38 105 91 102 238 27 123 290 224 38 259 79 199 84 193 14 128 25 21 191 237 17 256 259 233 187 10 160 59 19 276 114 174 169 175 74 18 7 235 69 145 198 179 58 252 32 255 111 62 82 278 183 285 230 229 32 68 135 39 269 67 230 75 44 263 168 165 86 108 16 92 112 105 58 114 20 181 78 107 265 237 276 268 162 266 142 119 201 258 36 52 77 64 118 109 26 80 22 96 80 71 60 29 143 24 44 191 132 114 279 193 152 140 99 54 25 54 179 42 276 9 150 192 109 285 92 217 129 35 180 101 228 160 213 7 81 81 219 231 134 167 1 231 272 179 196 264 227 117 237 171 244 185 200 61 72 119 152 2 87 272 284 220 241 1 77 284 82 229 219 44 158 144 188 20 27 90 10 6 71 93 17 69 283 210 82 91 207 262 4 18 79 271 120 73 113 164 181 265 83 288 50 195 221 251 281 108 275 104 186 138 184 223 61 88 95 175 107 6 225 81 114 207 157 101 41 184 190 73 162 128 130 45 168 11 98 11 170 47 221 146 257 131 88 23 139 56 199 189 217 283 23 106 68 273 51 51 100 64 13 85 49 185 233 49 290 257 26 64 46 73 267 152 107 111 249 58 9 288 204 183 26 218 34 170 234 197 169 70 50 41 233 154 22 234 92 145 93 155 81 186 243 208 200 248 48 21 86 213 40 69 178 186 105 196 126 215 214 204 45 14 23 1 44 4 156 91 53 274 199 51 205 88 282 151 130 232 144 34 32 222 123 136 236 112 34 137 246 100 31 25 159 203 19 171 90 197 274 94 27 228 22 201 104 48 126 110 190 227 150 225 97 90 230 262 20 286 102 84 39 26 31 58 147 8 278 216 273 35 75 77 251 94 132 252 291 267 185 95 37 95 224 71 247 5 166 250 84 144 50 8 245 228 55 189 30 15 172 149 28 133 157 134 29 110 36 239 53 87 223 28 100 169 37 62 236 266 280 131 104 291 162 161 118 142 14 177 281 141 263 30 153 12 75 182 275 71 198 41 46 178 291 129 173 192 4 261 115 30 48 280 98 116 194 24 116 227 12 213 194 57 104 153 150 87 85 16 197 136 82 124 195 67 263 63 141 109 42 56 45 201 120 24 149 215 109 180 68 240 63 246 133 19 122 126 248 202 9 183 180 206 252 137 279 88 128 163 33 265 270 264 73 8 140 204 78 2 241 76 ^ 622 0 89 183 111 180 34 85 59 159 256 154 207 210 115 75 10 108 168 78 209 68 103 176 269 272 55 35 10 51 33 38 87 31 123 258 69 36 172 202 161 171 277 169 3 22 236 179 109 93 70 83 29 36 67 121 49 61 74 85 116 2 97 244 11 33 160 246 285 1 42 89 118 87 260 99 159 134 289 247 38 152 55 222 14 110 255 42 211 277 226 138 62 64 216 204 11 270 25 206 163 258 241 171 212 30 198 266 195 254 239 84 69 28 283 143 54 167 153 217 194 142 64 151 65 206 220 99 281 293 249 125 116 57 137 137 72 48 128 78 152 227 63 54 232 177 22 129 68 168 21 74 28 275 254 174 60 149 93 242 218 184 158 37 162 39 249 3 251 212 80 59 52 260 34 20 214 60 27 228 282 46 106 253 249 68 275 17 15 100 271 15 43 136 269 100 214 289 182 14 53 120 2 89 240 246 220 156 122 39 77 162 96 90 43 79 134 60 92 252 202 96 147 178 119 77 97 72 170 287 38 30 190 83 136 147 235 254 117 219 109 265 205 238 266 73 95 100 206 285 123 201 49 290 50 280 66 253 192 227 235 189 93 5 59 224 101 74 257 251 40 239 19 224 223 233 102 129 3 144 101 139 281 56 90 165 238 94 232 55 157 284 11 205 1 107 113 217 22 7 203 29 143 111 8 193 45 116 122 276 236 7 268 53 242 161 49 118 209 125 238 37 97 15 35 247 210 287 210 50 51 205 173 127 153 45 59 102 121 114 85 288 135 157 219 166 106 66 66 188 53 13 185 148 168 250 50 108 46 213 70 190 140 271 187 63 291 97 137 194 207 88 250 115 132 145 263 290 115 10 280 9 118 37 105 198 94 60 214 117 47 268 110 83 201 171 155 10 43 144 273 274 27 293 12 260 156 174 117 284 133 70 255 164 76 237 104 101 261 146 16 262 243 143 176 32 113 95 157 47 31 245 123 29 208 135 222 243 86 41 286 285 58 62 129 240 9 61 17 244 76 172 80 2 32 105 91 98 234 27 121 286 220 34 257 79 199 84 191 8 128 21 17 187 235 17 252 259 231 187 6 156 57 15 272 112 170 165 173 70 18 5 231 65 141 196 179 52 252 30 255 107 56 82 276 179 281 228 225 26 66 131 33 267 63 226 73 38 259 166 163 86 106 16 90 108 103 54 110 18 177 72 105 263 233 274 264 158 266 138 119 199 256 32 48 71 58 112 105 26 74 20 92 80 67 56 25 141 24 44 191 130 108 275 189 150 140 99 52 23 54 175 42 276 7 146 188 103 283 86 213 127 31 180 99 224 158 209 3 79 77 219 231 130 165 1 229 272 177 194 264 223 111 237 169 240 181 196 57 72 113 152 292 87 268 282 218 241 293 77 284 76 229 80 ^ 635 1 40 150 140 184 12 23 78 294 2 67 93 9 57 283 206 74 83 199 254 4 6 67 263 120 61 113 156 181 257 79 284 46 191 213 251 273 100 271 100 186 138 184 223 61 76 83 175 107 6 217 81 114 207 149 89 29 180 182 73 158 120 122 37 160 11 98 295 162 35 221 146 249 123 88 19 139 48 191 189 213 275 15 98 60 273 39 51 96 60 1 77 49 181 233 41 286 257 18 64 42 65 263 144 99 111 241 58 1 288 196 179 22 214 30 170 226 197 169 66 42 41 225 146 14 234 92 145 89 155 69 178 243 208 200 244 48 21 78 209 40 65 178 182 97 196 118 207 210 200 33 10 23 289 36 152 79 49 266 195 43 201 84 274 151 130 228 136 34 24 214 115 132 228 112 292 26 129 238 92 19 13 159 195 19 163 86 189 274 90 19 224 10 193 104 40 126 102 186 223 146 225 85 90 230 262 8 278 90 80 39 14 23 54 147 4 278 216 265 35 75 73 243 82 124 248 283 267 185 87 29 95 220 71 243 293 162 246 72 144 38 237 228 51 181 22 3 288 172 141 24 129 153 130 17 98 36 235 41 75 219 20 88 165 25 54 232 262 280 131 92 291 162 161 110 142 14 173 277 141 259 18 149 4 67 178 267 59 198 33 34 170 287 121 173 192 288 257 103 26 44 276 90 104 186 12 108 227 213 190 53 96 145 150 79 73 8 193 128 78 124 187 63 263 59 137 109 30 44 41 201 108 16 149 215 105 176 56 232 51 242 133 7 118 122 248 198 9 183 172 202 244 133 279 80 124 163 25 265 270 260 69 8 132 204 74 294 237 252 89 179 107 176 32 85 53 157 256 154 205 210 115 71 8 108 166 76 209 64 103 176 267 270 49 31 10 47 31 34 85 29 119 258 69 32 170 202 159 171 277 165 1 16 234 177 107 91 70 83 29 34 67 117 47 55 72 83 114 292 2 91 240 7 33 160 246 283 291 36 85 114 81 260 93 155 130 289 247 38 150 55 222 10 108 251 38 211 275 226 136 58 62 212 200 9 268 25 204 159 256 239 167 212 30 194 264 195 254 239 82 63 28 279 141 48 167 151 215 190 138 58 147 65 202 220 95 281 291 247 123 112 57 137 133 68 42 126 78 148 225 61 52 232 177 22 129 68 168 15 74 22 275 250 174 56 147 89 240 218 180 158 35 160 35 245 293 247 208 74 59 52 256 28 20 214 54 21 224 282 46 106 251 249 62 273 15 13 98 271 15 37 136 269 100 210 285 182 12 47 116 292 87 240 242 218 156 120 37 75 158 96 84 39 75 134 58 86 250 198 94 145 174 117 71 93 70 168 287 36 24 190 77 134 143 235 252 113 217 105 261 205 234 262 69 93 94 206 285 121 197 43 286 46 276 66 253 188 223 231 187 87 5 57 222 95 285 ^ 636 0 251 248 37 233 16 224 220 230 102 123 3 141 98 133 278 56 84 165 235 91 229 49 157 278 2 202 295 98 110 217 19 1 203 20 137 108 5 193 42 116 122 270 236 7 268 47 242 155 43 115 206 125 238 28 94 6 32 244 207 284 204 50 42 199 167 127 153 45 53 93 121 111 79 282 129 151 213 166 97 57 60 188 53 10 182 148 162 244 47 105 37 210 61 187 137 268 184 63 285 97 134 194 201 82 250 112 132 142 257 290 109 4 277 3 118 37 96 195 94 60 211 114 47 265 110 80 198 168 149 1 43 138 267 268 24 287 12 257 153 288 171 117 281 130 67 252 164 76 231 101 101 261 143 13 256 237 143 173 32 107 89 154 44 31 245 123 26 202 135 216 240 80 38 286 279 55 62 126 237 6 55 8 244 70 166 74 293 23 105 91 92 228 27 118 280 214 28 254 79 199 84 188 296 128 15 11 181 232 17 246 259 228 187 150 54 9 266 109 164 159 170 64 18 2 225 59 135 193 179 43 252 27 255 101 47 82 273 173 275 225 219 17 63 125 24 264 57 220 70 29 253 163 160 86 103 16 87 102 100 48 104 15 171 63 102 260 227 271 258 152 266 132 119 196 253 26 42 62 49 103 99 26 65 17 86 80 61 50 19 138 24 44 191 127 99 269 183 147 140 99 49 20 54 169 42 276 4 140 182 94 280 77 207 124 25 180 96 218 155 203 294 76 71 219 231 124 162 1 226 272 174 191 264 217 102 237 166 234 175 190 51 72 104 152 289 87 262 279 215 241 293 77 284 67 229 209 39 148 139 183 10 22 75 292 1 66 93 7 54 283 205 72 81 197 252 4 3 64 261 120 58 113 154 181 255 78 283 45 190 211 251 271 98 270 99 186 138 184 223 61 73 80 175 107 6 215 81 114 207 147 86 26 179 180 73 157 118 120 35 158 11 98 293 160 32 221 146 247 121 88 18 139 46 189 189 212 273 13 96 58 273 36 51 95 59 295 75 49 180 233 39 285 257 16 64 41 63 262 142 97 111 239 58 296 288 194 178 21 213 29 170 224 197 169 65 40 41 223 144 12 234 92 145 88 155 66 176 243 208 200 243 48 21 76 208 40 64 178 181 95 196 116 205 209 199 30 9 23 288 34 296 151 76 48 264 194 41 200 83 272 151 130 227 134 34 22 212 113 131 226 112 292 24 127 236 90 16 10 159 193 19 161 85 187 274 89 17 223 7 191 104 38 126 100 185 222 145 225 82 90 230 262 5 276 87 79 39 11 21 53 147 3 278 216 263 35 75 72 241 79 122 247 281 267 185 85 27 95 219 71 242 292 161 245 69 144 35 295 235 228 50 179 20 287 172 139 23 128 152 129 14 95 36 234 38 72 218 18 85 164 22 52 231 261 280 131 89 291 162 161 108 142 14 172 276 91 ^ 635 1 256 9 146 297 61 175 261 50 198 27 25 164 284 115 173 192 282 254 94 23 41 273 84 95 180 3 102 227 290 213 187 50 90 139 150 73 64 2 190 122 75 124 181 60 263 56 134 109 21 35 38 201 99 10 149 215 102 173 47 226 42 239 133 297 115 119 248 195 9 183 166 199 238 130 279 74 121 163 19 265 270 257 66 8 126 204 71 294 234 246 89 173 101 170 29 85 44 154 256 154 202 210 115 65 5 108 163 73 209 58 103 176 264 267 40 25 10 41 28 28 82 26 113 258 69 26 167 202 156 171 277 159 297 7 231 174 104 88 70 83 29 31 67 111 44 46 69 80 111 289 2 82 234 1 33 160 246 280 285 27 79 108 72 260 84 149 124 289 247 38 147 55 222 4 105 245 32 211 272 226 133 52 59 206 194 6 265 25 201 153 253 236 161 212 30 188 261 195 254 239 79 54 28 273 138 39 167 148 212 184 132 49 141 65 196 220 89 281 288 244 120 106 57 137 127 62 33 123 78 142 222 58 49 232 177 22 129 68 168 6 74 13 275 244 174 50 144 83 237 218 174 158 32 157 29 239 287 241 202 65 59 52 250 19 20 214 45 12 218 282 46 106 248 249 53 270 12 10 95 271 15 28 136 269 100 204 279 182 9 38 110 286 84 240 236 215 156 117 34 72 152 96 75 33 69 134 55 77 247 192 91 142 168 114 62 87 67 165 287 33 15 190 68 131 137 235 249 107 214 99 255 205 228 256 63 90 85 206 285 118 191 34 280 40 270 66 253 182 217 225 184 78 5 54 219 86 64 247 246 35 229 14 224 218 228 102 119 3 139 96 129 276 56 80 165 233 89 227 45 157 274 295 200 295 92 108 217 17 296 203 14 133 106 3 193 40 116 122 266 236 7 268 43 242 151 39 113 204 125 238 22 92 30 242 205 282 200 50 36 195 163 127 153 45 49 87 121 109 75 278 125 147 209 166 91 51 56 188 53 8 180 148 158 240 45 103 31 208 55 185 135 266 182 63 281 97 132 194 197 78 250 110 132 140 253 290 105 275 298 118 37 90 193 94 60 209 112 47 263 110 78 196 166 145 294 43 134 263 264 22 283 12 255 151 284 169 117 279 128 65 250 164 76 227 99 101 261 141 11 252 233 143 171 32 103 85 152 42 31 245 123 24 198 135 212 238 76 36 286 275 53 62 124 235 4 51 2 244 66 162 70 291 17 105 91 88 224 27 116 276 210 24 252 79 199 84 186 292 128 11 7 177 230 17 242 259 226 187 295 146 52 5 262 107 160 155 168 60 18 221 55 131 191 179 37 252 25 255 97 41 82 271 169 271 223 215 11 61 121 18 262 53 216 68 23 249 161 158 86 101 16 85 98 98 44 100 13 167 57 100 258 223 269 254 148 266 128 119 194 251 22 38 56 43 275 ^ 642 0 91 26 53 13 78 80 53 42 11 134 24 44 191 123 87 261 175 143 140 99 45 16 54 161 42 276 132 174 82 276 65 199 120 17 180 92 210 151 195 290 72 63 219 231 116 158 1 222 272 170 187 264 209 90 237 162 226 167 182 43 72 92 152 285 87 254 275 211 241 293 77 284 55 229 201 35 140 135 179 2 18 63 284 298 62 93 300 42 283 201 64 73 189 244 4 292 52 253 120 46 113 146 181 247 74 279 41 186 203 251 263 90 266 95 186 138 184 223 61 61 68 175 107 6 207 81 114 207 139 74 14 175 172 73 153 110 112 27 150 11 98 285 152 20 221 146 239 113 88 14 139 38 181 189 208 265 5 88 50 273 24 51 91 55 287 67 49 176 233 31 281 257 8 64 37 55 258 134 89 111 231 58 292 288 186 174 17 209 25 170 216 197 169 61 32 41 215 136 4 234 92 145 84 155 54 168 243 208 200 239 48 21 68 204 40 60 178 177 87 196 108 197 205 195 18 5 23 284 26 296 147 64 44 256 190 33 196 79 264 151 130 223 126 34 14 204 105 127 218 112 292 16 119 228 82 4 299 159 185 19 153 81 179 274 85 9 219 296 183 104 30 126 92 181 218 141 225 70 90 230 262 294 268 75 75 39 300 13 49 147 300 278 216 255 35 75 68 233 67 114 243 273 267 185 77 19 95 215 71 238 288 157 241 57 144 23 291 227 228 46 171 12 289 283 172 131 19 124 148 125 2 83 36 230 26 60 214 10 73 160 10 44 227 257 280 131 77 291 162 161 100 142 14 168 272 141 254 3 144 295 57 173 257 44 198 23 19 160 282 111 173 192 278 252 88 21 39 271 80 89 176 298 98 227 286 213 185 48 86 135 150 69 58 299 188 118 73 124 177 58 263 54 132 109 15 29 36 201 93 6 149 215 100 171 41 222 36 237 133 293 113 117 248 193 9 183 162 197 234 128 279 70 119 163 15 265 270 255 64 8 122 204 69 294 232 242 89 169 97 166 27 85 38 152 256 154 200 210 115 61 3 108 161 71 209 54 103 176 262 265 34 21 10 37 26 24 80 24 109 258 69 22 165 202 154 171 277 155 297 1 229 172 102 86 70 83 29 29 67 107 42 40 67 78 109 287 2 76 230 298 33 160 246 278 281 21 75 104 66 260 78 145 120 289 247 38 145 55 222 103 241 28 211 270 226 131 48 57 202 190 4 263 25 199 149 251 234 157 212 30 184 259 195 254 239 77 48 28 269 136 33 167 146 210 180 128 43 137 65 192 220 85 281 286 242 118 102 57 137 123 58 27 121 78 138 220 56 47 232 177 22 129 68 168 74 7 275 240 174 46 142 79 235 218 170 158 30 155 25 235 283 237 198 59 59 52 246 13 20 214 39 6 214 282 46 106 246 249 47 268 10 8 93 271 15 22 136 269 100 200 275 42 ^ 644 0 6 29 104 280 81 240 230 212 156 114 31 69 146 96 66 27 63 134 52 68 244 186 88 139 162 111 53 81 64 162 287 30 6 190 59 128 131 235 246 101 211 93 249 205 222 250 57 87 76 206 285 115 185 25 274 34 264 66 253 176 211 219 181 69 5 51 216 77 58 241 243 32 223 11 224 215 225 102 113 3 136 93 123 273 56 74 165 230 86 224 39 157 268 289 197 295 83 105 217 14 293 203 5 127 103 193 37 116 122 260 236 7 268 37 242 145 33 110 201 125 238 13 89 293 27 239 202 279 194 50 27 189 157 127 153 45 43 78 121 106 69 272 119 141 203 166 82 42 50 188 53 5 177 148 152 234 42 100 22 205 46 182 132 263 179 63 275 97 129 194 191 72 250 107 132 137 247 290 99 296 272 295 118 37 81 190 94 60 206 109 47 260 110 75 193 163 139 288 43 128 257 258 19 277 12 252 148 278 166 117 276 125 62 247 164 76 221 96 101 261 138 8 246 227 143 168 32 97 79 149 39 31 245 123 21 192 135 206 235 70 33 286 269 50 62 121 232 1 45 295 244 60 156 64 288 8 105 91 82 218 27 113 270 204 18 249 79 199 84 183 286 128 5 1 171 227 17 236 259 223 187 292 140 49 301 256 104 154 149 165 54 18 299 215 49 125 188 179 28 252 22 255 91 32 82 268 163 265 220 209 2 58 115 9 259 47 210 65 14 243 158 155 86 98 16 82 92 95 38 94 10 161 48 97 255 217 266 248 142 266 122 119 191 248 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 191 122 84 259 173 142 140 99 44 15 54 159 42 276 301 130 172 79 275 62 197 119 15 180 91 208 150 193 289 71 61 219 231 114 157 1 221 272 169 186 264 207 87 237 161 224 165 180 41 72 89 152 284 87 252 274 210 241 293 77 284 52 229 199 34 138 134 178 17 60 282 298 61 93 299 39 283 200 62 71 187 242 4 290 49 251 120 43 113 144 181 245 73 278 40 185 201 251 261 88 265 94 186 138 184 223 61 58 65 175 107 6 205 81 114 207 137 71 11 174 170 73 152 108 110 25 148 11 98 283 150 17 221 146 237 111 88 13 139 36 179 189 207 263 3 86 48 273 21 51 90 54 285 65 49 175 233 29 280 257 6 64 36 53 257 132 87 111 229 58 291 288 184 173 16 208 24 170 214 197 169 60 30 41 213 134 2 234 92 145 83 155 51 166 243 208 200 238 48 21 66 203 40 59 178 176 85 196 106 195 204 194 15 4 23 283 24 296 146 61 43 254 189 31 195 78 262 151 130 222 124 34 12 202 103 126 216 112 292 14 117 226 80 1 297 159 183 19 151 80 177 274 84 7 218 294 181 104 28 126 90 180 217 140 225 67 90 230 262 292 266 72 74 39 298 11 48 147 300 278 216 253 265 ^ 638 1 75 65 227 58 108 240 267 267 185 71 13 95 212 71 235 285 154 238 48 144 14 288 221 228 43 165 6 283 280 172 125 16 121 145 122 297 74 36 227 17 51 211 4 64 157 1 38 224 254 280 131 68 291 162 161 94 142 14 165 269 141 251 298 141 292 51 170 251 35 198 17 10 154 279 105 173 192 272 249 79 18 36 268 74 80 170 292 92 227 280 213 182 45 80 129 150 63 49 296 185 112 70 124 171 55 263 51 129 109 6 20 33 201 84 149 215 97 168 32 216 27 234 133 287 110 114 248 190 9 183 156 194 228 125 279 64 116 163 9 265 270 252 61 8 116 204 66 294 229 236 89 163 91 160 24 85 29 149 256 154 197 210 115 55 108 158 68 209 48 103 176 259 262 25 15 10 31 23 18 77 21 103 258 69 16 162 202 151 171 277 149 297 296 226 169 99 83 70 83 29 26 67 101 39 31 64 75 106 284 2 67 224 295 33 160 246 275 275 12 69 98 57 260 69 139 114 289 247 38 142 55 222 298 100 235 22 211 267 226 128 42 54 196 184 1 260 25 196 143 248 231 151 212 30 178 256 195 254 239 74 39 28 263 133 24 167 143 207 174 122 34 131 65 186 220 79 281 283 239 115 96 57 137 117 52 18 118 78 132 217 53 44 232 177 22 129 68 168 295 74 302 275 234 174 40 139 73 232 218 164 158 27 152 19 229 277 231 192 50 59 52 240 4 20 214 30 301 208 282 46 106 243 249 38 265 7 5 90 271 15 13 136 269 100 194 269 182 4 23 100 276 79 240 226 210 156 112 29 67 142 96 60 23 59 134 50 62 242 182 86 137 158 109 47 77 62 160 287 28 190 53 126 127 235 244 97 209 89 245 205 218 246 53 85 70 206 285 113 181 19 270 30 260 66 253 172 207 215 179 63 5 49 214 71 54 237 241 30 219 9 224 213 223 102 109 3 134 91 119 271 56 70 165 228 84 222 35 157 264 285 195 295 77 103 217 12 291 203 303 123 101 302 193 35 116 122 256 236 7 268 33 242 141 29 108 199 125 238 7 87 289 25 237 200 277 190 50 21 185 153 127 153 45 39 72 121 104 65 268 115 137 199 166 76 36 46 188 53 3 175 148 148 230 40 98 16 203 40 180 130 261 177 63 271 97 127 194 187 68 250 105 132 135 243 290 95 294 270 293 118 37 75 188 94 60 204 107 47 258 110 73 191 161 135 284 43 124 253 254 17 273 12 250 146 274 164 117 274 123 60 245 164 76 217 94 101 261 136 6 242 223 143 166 32 93 75 147 37 31 245 123 19 188 135 202 233 66 31 286 265 48 62 119 230 303 41 291 244 56 152 60 286 2 105 91 78 214 27 111 266 200 14 247 79 199 84 181 282 128 1 301 167 225 17 232 259 221 187 290 136 47 299 252 102 150 145 163 157 ^ 653 0 18 299 207 41 117 184 179 16 252 18 255 83 20 82 264 155 257 216 201 296 54 107 303 255 39 202 61 2 235 154 151 86 94 16 78 84 91 30 86 6 153 36 93 251 209 262 240 134 266 114 119 187 244 8 24 35 22 76 81 26 38 8 68 80 43 32 1 129 24 44 191 118 72 251 165 138 140 99 40 11 54 151 42 276 301 122 164 67 271 50 189 115 7 180 87 200 146 185 285 67 53 219 231 106 153 1 217 272 165 182 264 199 75 237 157 216 157 172 33 72 77 152 280 87 244 270 206 241 293 77 284 40 229 191 30 130 130 174 298 13 48 274 298 57 93 295 27 283 196 54 63 179 234 4 282 37 243 120 31 113 136 181 237 69 274 36 181 193 251 253 80 261 90 186 138 184 223 61 46 53 175 107 6 197 81 114 207 129 59 305 170 162 73 148 100 102 17 140 11 98 275 142 5 221 146 229 103 88 9 139 28 171 189 203 255 301 78 40 273 9 51 86 50 277 57 49 171 233 21 276 257 304 64 32 45 253 124 79 111 221 58 287 288 176 169 12 204 20 170 206 197 169 56 22 41 205 126 300 234 92 145 79 155 39 158 243 208 200 234 48 21 58 199 40 55 178 172 77 196 98 187 200 190 3 23 279 16 296 142 49 39 246 185 23 191 74 254 151 130 218 116 34 4 194 95 122 208 112 292 6 109 218 72 295 289 159 175 19 143 76 169 274 80 305 214 286 173 104 20 126 82 176 213 136 225 55 90 230 262 284 258 60 70 39 290 3 44 147 300 278 216 245 35 75 63 223 52 104 238 263 267 185 67 9 95 210 71 233 283 152 236 42 144 8 286 217 228 41 161 2 279 278 172 121 14 119 143 120 293 68 36 225 11 45 209 58 155 301 34 222 252 280 131 62 291 162 161 90 142 14 163 267 141 249 294 139 290 47 168 247 29 198 13 4 150 277 101 173 192 268 247 73 16 34 266 70 74 166 288 88 227 276 213 180 43 76 125 150 59 43 294 183 108 68 124 167 53 263 49 127 109 14 31 201 78 302 149 215 95 166 26 212 21 232 133 283 108 112 248 188 9 183 152 192 224 123 279 60 114 163 5 265 270 250 59 8 112 204 64 294 227 232 89 159 87 156 22 85 23 147 256 154 195 210 115 51 304 108 156 66 209 44 103 176 257 260 19 11 10 27 21 14 75 19 99 258 69 12 160 202 149 171 277 145 297 292 224 167 97 81 70 83 29 24 67 97 37 25 62 73 104 282 2 61 220 293 33 160 246 273 271 6 65 94 51 260 63 135 110 289 247 38 140 55 222 296 98 231 18 211 265 226 126 38 52 192 180 305 258 25 194 139 246 229 147 212 30 174 254 195 254 239 72 33 28 259 131 18 167 141 205 170 118 28 127 65 182 220 75 281 281 237 113 92 57 137 113 48 12 116 78 128 215 51 42 232 177 22 129 68 168 291 161 ^ 653 0 296 275 228 174 34 136 67 229 218 158 158 24 149 13 223 271 225 186 41 59 52 234 302 20 214 21 295 202 282 46 106 240 249 29 262 4 2 87 271 15 4 136 269 100 188 263 182 1 14 94 270 76 240 220 207 156 109 26 64 136 96 51 17 53 134 47 53 239 176 83 134 152 106 38 71 59 157 287 25 298 190 44 123 121 235 241 91 206 83 239 205 212 240 47 82 61 206 285 110 175 10 264 24 254 66 253 166 201 209 176 54 5 46 211 62 48 231 238 27 213 6 224 210 220 102 103 3 131 88 113 268 56 64 165 225 81 219 29 157 258 279 192 295 68 100 217 9 288 203 297 117 98 302 193 32 116 122 250 236 7 268 27 242 135 23 105 196 125 238 305 84 283 22 234 197 274 184 50 12 179 147 127 153 45 33 63 121 101 59 262 109 131 193 166 67 27 40 188 53 172 148 142 224 37 95 7 200 31 177 127 258 174 63 265 97 124 194 181 62 250 102 132 132 237 290 89 291 267 290 118 37 66 185 94 60 201 104 47 255 110 70 188 158 129 278 43 118 247 248 14 267 12 247 143 268 161 117 271 120 57 242 164 76 211 91 101 261 133 3 236 217 143 163 32 87 69 144 34 31 245 123 16 182 135 196 230 60 28 286 259 45 62 116 227 303 35 285 244 50 146 54 283 300 105 91 72 208 27 108 260 194 8 244 79 199 84 178 276 128 302 298 161 222 17 226 259 218 187 287 130 44 296 246 99 144 139 160 44 18 299 205 39 115 183 179 13 252 17 255 81 17 82 263 153 255 215 199 294 53 105 301 254 37 200 60 306 233 153 150 86 93 16 77 82 90 28 84 5 151 33 92 250 207 261 238 132 266 112 119 186 243 6 22 32 19 73 79 26 35 7 66 80 41 30 306 128 24 44 191 117 69 249 163 137 140 99 39 10 54 149 42 276 301 120 162 64 270 47 187 114 5 180 86 198 145 183 284 66 51 219 231 104 152 1 216 272 164 181 264 197 72 237 156 214 155 170 31 72 74 152 279 87 242 269 205 241 293 77 284 37 229 189 29 128 129 173 297 12 45 272 298 56 93 294 24 283 195 52 61 177 232 4 280 34 241 120 28 113 134 181 235 68 273 35 180 191 251 251 78 260 89 186 138 184 223 61 43 50 175 107 6 195 81 114 207 127 56 303 169 160 73 147 98 100 15 138 11 98 273 140 2 221 146 227 101 88 8 139 26 169 189 202 253 300 76 38 273 6 51 85 49 275 55 49 170 233 19 275 257 303 64 31 43 252 122 77 111 219 58 286 288 174 168 11 203 19 170 204 197 169 55 20 41 203 124 299 234 92 145 78 155 36 156 243 208 200 233 48 21 56 198 40 54 178 171 75 196 96 185 199 189 306 23 278 14 296 141 46 38 244 184 21 190 73 252 151 130 217 114 34 2 192 93 121 206 112 292 4 107 216 70 293 112 ^ 646 1 159 169 19 137 73 163 274 77 302 211 280 167 104 14 126 76 173 210 133 225 46 90 230 262 278 252 51 67 39 284 306 41 147 300 278 216 239 35 75 60 217 43 98 235 257 267 185 61 3 95 207 71 230 280 149 233 33 144 308 283 211 228 38 155 305 273 275 172 115 11 116 140 117 287 59 36 222 2 36 206 303 49 152 295 28 219 249 280 131 53 291 162 161 84 142 14 160 264 141 246 288 136 287 41 165 241 20 198 7 304 144 274 95 173 192 262 244 64 13 31 263 64 65 160 282 82 227 270 213 177 40 70 119 150 53 34 291 180 102 65 124 161 50 263 46 124 109 300 5 28 201 69 299 149 215 92 163 17 206 12 229 133 277 105 109 248 185 9 183 146 189 218 120 279 54 111 163 308 265 270 247 56 8 106 204 61 294 224 226 89 153 81 150 19 85 14 144 256 154 192 210 115 45 304 108 153 63 209 38 103 176 254 257 10 5 10 21 18 8 72 16 93 258 69 6 157 202 146 171 277 139 297 286 221 164 94 78 70 83 29 21 67 91 34 16 59 70 101 279 2 52 214 290 33 160 246 270 265 306 59 88 42 260 54 129 104 289 247 38 137 55 222 293 95 225 12 211 262 226 123 32 49 186 174 305 255 25 191 133 243 226 141 212 30 168 251 195 254 239 69 24 28 253 128 9 167 138 202 164 112 19 121 65 176 220 69 281 278 234 110 86 57 137 107 42 3 113 78 122 212 48 39 232 177 22 129 68 168 285 74 292 275 224 174 30 134 63 227 218 154 158 22 147 9 219 267 221 182 35 59 52 230 298 20 214 15 291 198 282 46 106 238 249 23 260 2 85 271 15 307 136 269 100 184 259 182 308 8 90 266 74 240 216 205 156 107 24 62 132 96 45 13 49 134 45 47 237 172 81 132 148 104 32 67 57 155 287 23 294 190 38 121 117 235 239 87 204 79 235 205 208 236 43 80 55 206 285 108 171 4 260 20 250 66 253 162 197 205 174 48 5 44 209 56 44 227 236 25 209 4 224 208 218 102 99 3 129 86 109 266 56 60 165 223 79 217 25 157 254 275 190 295 62 98 217 7 286 203 293 113 96 302 193 30 116 122 246 236 7 268 23 242 131 19 103 194 125 238 301 82 279 20 232 195 272 180 50 6 175 143 127 153 45 29 57 121 99 55 258 105 127 189 166 61 21 36 188 53 307 170 148 138 220 35 93 1 198 25 175 125 256 172 63 261 97 122 194 177 58 250 100 132 130 233 290 85 289 265 288 118 37 60 183 94 60 199 102 47 253 110 68 186 156 125 274 43 114 243 244 12 263 12 245 141 264 159 117 269 118 55 240 164 76 207 89 101 261 131 1 232 213 143 161 32 83 65 142 32 31 245 123 14 178 135 192 228 56 26 286 255 43 62 114 225 303 31 281 244 46 142 50 281 296 105 91 238 ^ 647 0 200 27 104 252 186 240 79 199 84 174 268 128 298 294 153 218 17 218 259 214 187 283 122 40 292 238 95 136 131 156 36 18 299 197 31 107 179 179 1 252 13 255 73 5 82 259 145 247 211 191 286 49 97 293 250 29 192 56 298 225 149 146 86 89 16 73 74 86 20 76 1 143 21 88 246 199 257 230 124 266 104 119 182 239 309 14 20 7 61 71 26 23 3 58 80 33 22 302 124 24 44 191 113 57 241 155 133 140 99 35 6 54 141 42 276 301 112 154 52 266 35 179 110 308 180 82 190 141 175 280 62 43 219 231 96 148 1 212 272 160 177 264 189 60 237 152 206 147 162 23 72 62 152 275 87 234 265 201 241 293 77 284 25 229 181 25 120 125 169 293 8 33 264 298 52 93 290 12 283 191 44 53 169 224 4 272 22 233 120 16 113 126 181 227 64 269 31 176 183 251 243 70 256 85 186 138 184 223 61 31 38 175 107 6 187 81 114 207 119 44 295 165 152 73 143 90 92 7 130 11 98 265 132 301 221 146 219 93 88 4 139 18 161 189 198 245 296 68 30 273 305 51 81 45 267 47 49 166 233 11 271 257 299 64 27 35 248 114 69 111 211 58 282 288 166 164 7 199 15 170 196 197 169 51 12 41 195 116 295 234 92 145 74 155 24 148 243 208 200 229 48 21 48 194 40 50 178 167 67 196 88 177 195 185 299 306 23 274 6 296 137 34 34 236 180 13 186 69 244 151 130 213 106 34 305 184 85 117 198 112 292 307 99 208 62 285 279 159 165 19 133 71 159 274 75 300 209 276 163 104 10 126 72 171 208 131 225 40 90 230 262 274 248 45 65 39 280 304 39 147 300 278 216 235 35 75 58 213 37 94 233 253 267 185 57 310 95 205 71 228 278 147 231 27 144 304 281 207 228 36 151 303 269 273 172 111 9 114 138 115 283 53 36 220 307 30 204 301 43 150 291 24 217 247 280 131 47 291 162 161 80 142 14 158 262 141 244 284 134 285 37 163 237 14 198 3 300 140 272 91 173 192 258 242 58 11 29 261 60 59 156 278 78 227 266 213 175 38 66 115 150 49 28 289 178 98 63 124 157 48 263 44 122 109 296 310 26 201 63 297 149 215 90 161 11 202 6 227 133 273 103 107 248 183 9 183 142 187 214 118 279 50 109 163 306 265 270 245 54 8 102 204 59 294 222 222 89 149 77 146 17 85 8 142 256 154 190 210 115 41 304 108 151 61 209 34 103 176 252 255 4 1 10 17 16 4 70 14 89 258 69 2 155 202 144 171 277 135 297 282 219 162 92 76 70 83 29 19 67 87 32 10 57 68 99 277 2 46 210 288 33 160 246 268 261 302 55 84 36 260 48 125 100 289 247 38 135 55 222 291 93 221 8 211 260 226 121 28 47 182 170 305 253 25 189 129 241 224 137 212 30 164 249 195 254 239 86 ^ 665 0 15 28 247 125 167 135 199 158 106 10 115 65 170 220 63 281 275 231 107 80 57 137 101 36 306 110 78 116 209 45 36 232 177 22 129 68 168 279 74 286 275 218 174 24 131 57 224 218 148 158 19 144 3 213 261 215 176 26 59 52 224 292 20 214 6 285 192 282 46 106 235 249 14 257 311 309 82 271 15 301 136 269 100 178 253 182 308 311 84 260 71 240 210 202 156 104 21 59 126 96 36 7 43 134 42 38 234 166 78 129 142 101 23 61 54 152 287 20 288 190 29 118 111 235 236 81 201 73 229 205 202 230 37 77 46 206 285 105 165 307 254 14 244 66 253 156 191 199 171 39 5 41 206 47 38 221 233 22 203 1 224 205 215 102 93 3 126 83 103 263 56 54 165 220 76 214 19 157 248 269 187 295 53 95 217 4 283 203 287 107 93 302 193 27 116 122 240 236 7 268 17 242 125 13 100 191 125 238 295 79 273 17 229 192 269 174 50 309 169 137 127 153 45 23 48 121 96 49 252 99 121 183 166 52 12 30 188 53 307 167 148 132 214 32 90 304 195 16 172 122 253 169 63 255 97 119 194 171 52 250 97 132 127 227 290 79 286 262 285 118 37 51 180 94 60 196 99 47 250 110 65 183 153 119 268 43 108 237 238 9 257 12 242 138 258 156 117 266 115 52 237 164 76 201 86 101 261 128 310 226 207 143 158 32 77 59 139 29 31 245 123 11 172 135 186 225 50 23 286 249 40 62 111 222 303 25 275 244 40 136 44 278 290 105 91 62 198 27 103 250 184 310 239 79 199 84 173 266 128 297 293 151 217 17 216 259 213 187 282 120 39 291 236 94 134 129 155 34 18 299 195 29 105 178 179 310 252 12 255 71 2 82 258 143 245 210 189 284 48 95 291 249 27 190 55 296 223 148 145 86 88 16 72 72 85 18 74 141 18 87 245 197 256 228 122 266 102 119 181 238 308 12 17 4 58 69 26 20 2 56 80 31 20 301 123 24 44 191 112 54 239 153 132 140 99 34 5 54 139 42 276 301 110 152 49 265 32 177 109 307 180 81 188 140 173 279 61 41 219 231 94 147 1 211 272 159 176 264 187 57 237 151 204 145 160 21 72 59 152 274 87 232 264 200 241 293 77 284 22 229 179 24 118 124 168 292 7 30 262 298 51 93 289 9 283 190 42 51 167 222 4 270 19 231 120 13 113 124 181 225 63 268 30 175 181 251 241 68 255 84 186 138 184 223 61 28 35 175 107 6 185 81 114 207 117 41 293 164 150 73 142 88 90 5 128 11 98 263 130 299 221 146 217 91 88 3 139 16 159 189 197 243 295 66 28 273 303 51 80 44 265 45 49 165 233 9 270 257 298 64 26 33 247 112 67 111 209 58 281 288 164 163 6 198 14 170 194 197 169 50 10 41 193 114 294 234 92 145 73 155 21 146 243 208 200 228 48 21 46 193 40 49 178 166 65 196 86 175 194 184 297 306 23 273 206 ^ 641 0 296 134 25 31 230 177 7 183 66 238 151 130 210 100 34 302 178 79 114 192 112 292 304 93 202 56 279 273 159 159 19 127 68 153 274 72 297 206 270 157 104 4 126 66 168 205 128 225 31 90 230 262 268 242 36 62 39 274 301 36 147 300 278 216 229 35 75 55 207 28 88 230 247 267 185 51 307 95 202 71 225 275 144 228 18 144 298 278 201 228 33 145 300 263 270 172 105 6 111 135 112 277 44 36 217 301 21 201 298 34 147 285 18 214 244 280 131 38 291 162 161 74 142 14 155 259 141 241 278 131 282 31 160 231 5 198 311 294 134 269 85 173 192 252 239 49 8 26 258 54 50 150 272 72 227 260 213 172 35 60 109 150 43 19 286 175 92 60 124 151 45 263 41 119 109 290 304 23 201 54 294 149 215 87 158 2 196 311 224 133 267 100 104 248 180 9 183 136 184 208 115 279 44 106 163 303 265 270 242 51 8 96 204 56 294 219 216 89 143 71 140 14 85 313 139 256 154 187 210 115 35 304 108 148 58 209 28 103 176 249 252 309 309 10 11 13 312 67 11 83 258 69 310 152 202 141 171 277 129 297 276 216 159 89 73 70 83 29 16 67 81 29 1 54 65 96 274 2 37 204 285 33 160 246 265 255 296 49 78 27 260 39 119 94 289 247 38 132 55 222 288 90 215 2 211 257 226 118 22 44 176 164 305 250 25 186 123 238 221 131 212 30 158 246 195 254 239 64 9 28 243 123 308 167 133 197 154 102 4 111 65 166 220 59 281 273 229 105 76 57 137 97 32 302 108 78 112 207 43 34 232 177 22 129 68 168 275 74 282 275 214 174 20 129 53 222 218 144 158 17 142 313 209 257 211 172 20 59 52 220 288 20 214 281 188 282 46 106 233 249 8 255 311 309 80 271 15 297 136 269 100 174 249 182 308 307 80 256 69 240 206 200 156 102 19 57 122 96 30 3 39 134 40 32 232 162 76 127 138 99 17 57 52 150 287 18 284 190 23 116 107 235 234 77 199 69 225 205 198 226 33 75 40 206 285 103 161 303 250 10 240 66 253 152 187 195 169 33 5 39 204 41 34 217 231 20 199 313 224 203 213 102 89 3 124 81 99 261 56 50 165 218 74 212 15 157 244 265 185 295 47 93 217 2 281 203 283 103 91 302 193 25 116 122 236 236 7 268 13 242 121 9 98 189 125 238 291 77 269 15 227 190 267 170 50 305 165 133 127 153 45 19 42 121 94 45 248 95 117 179 166 46 6 26 188 53 307 165 148 128 210 30 88 300 193 10 170 120 251 167 63 251 97 117 194 167 48 250 95 132 125 223 290 75 284 260 283 118 37 45 178 94 60 194 97 47 248 110 63 181 151 115 264 43 104 233 234 7 253 12 240 136 254 154 117 264 113 50 235 164 76 197 84 101 261 126 310 222 203 143 276 ^ 656 0 32 69 51 135 25 31 245 123 7 164 135 178 221 42 19 286 241 36 62 107 218 303 17 267 244 32 128 36 274 282 105 91 54 190 27 99 242 176 306 235 79 199 84 169 258 128 293 289 143 213 17 208 259 209 187 278 112 35 287 228 90 126 121 151 26 18 299 187 21 97 174 179 302 252 8 255 63 306 82 254 135 237 206 181 276 44 87 283 245 19 182 51 288 215 144 141 86 84 16 68 64 81 10 66 312 133 6 83 241 189 252 220 114 266 94 119 177 234 304 4 5 308 46 61 26 8 314 48 80 23 12 297 119 24 44 191 108 42 231 145 128 140 99 30 1 54 131 42 276 301 102 144 37 261 20 169 105 303 180 77 180 136 165 275 57 33 219 231 86 143 1 207 272 155 172 264 179 45 237 147 196 137 152 13 72 47 152 270 87 224 260 196 241 293 77 284 10 229 171 20 110 120 164 288 3 18 254 298 47 93 285 313 283 186 34 43 159 214 4 262 7 223 120 1 113 116 181 217 59 264 26 171 173 251 233 60 251 80 186 138 184 223 61 16 23 175 107 6 177 81 114 207 109 29 285 160 142 73 138 80 82 313 120 11 98 255 122 291 221 146 209 83 88 315 139 8 151 189 193 235 291 58 20 273 295 51 76 40 257 37 49 161 233 1 266 257 294 64 22 25 243 104 59 111 201 58 277 288 156 159 2 194 10 170 186 197 169 46 2 41 185 106 290 234 92 145 69 155 9 138 243 208 200 224 48 21 38 189 40 45 178 162 57 196 78 167 190 180 289 306 23 269 312 296 132 19 29 226 175 3 181 64 234 151 130 208 96 34 300 174 75 112 188 112 292 302 89 198 52 275 269 159 155 19 123 66 149 274 70 295 204 266 153 104 126 62 166 203 126 225 25 90 230 262 264 238 30 60 39 270 299 34 147 300 278 216 225 35 75 53 203 22 84 228 243 267 185 47 305 95 200 71 223 273 142 226 12 144 294 276 197 228 31 141 298 259 268 172 101 4 109 133 110 273 38 36 215 297 15 199 296 28 145 281 14 212 242 280 131 32 291 162 161 70 142 14 153 257 141 239 274 129 280 27 158 227 315 198 309 290 130 267 81 173 192 248 237 43 6 24 256 50 44 146 268 68 227 256 213 170 33 56 105 150 39 13 284 173 88 58 124 147 43 263 39 117 109 286 300 21 201 48 292 149 215 85 156 312 192 307 222 133 263 98 102 248 178 9 183 132 182 204 113 279 40 104 163 301 265 270 240 49 8 92 204 54 294 217 212 89 139 67 136 12 85 309 137 256 154 185 210 115 31 304 108 146 56 209 24 103 176 247 250 305 307 10 7 11 310 65 9 79 258 69 308 150 202 139 171 277 125 297 272 214 157 87 71 70 83 29 14 67 77 27 311 52 63 94 272 2 31 200 283 33 160 246 263 251 292 45 74 21 260 33 115 90 289 247 38 130 55 222 286 88 211 227 ^ 668 0 211 254 226 115 16 41 170 158 305 247 25 183 117 235 218 125 212 30 152 243 195 254 239 61 28 237 120 302 167 130 194 148 96 312 105 65 160 220 53 281 270 226 102 70 57 137 91 26 296 105 78 106 204 40 31 232 177 22 129 68 168 269 74 276 275 208 174 14 126 47 219 218 138 158 14 139 310 203 251 205 166 11 59 52 214 282 20 214 308 275 182 282 46 106 230 249 316 252 311 309 77 271 15 291 136 269 100 168 243 182 308 301 74 250 66 240 200 197 156 99 16 54 116 96 21 314 33 134 37 23 229 156 73 124 132 96 8 51 49 147 287 15 278 190 14 113 101 235 231 71 196 63 219 205 192 220 27 72 31 206 285 100 155 297 244 4 234 66 253 146 181 189 166 24 5 36 201 32 28 211 228 17 193 313 224 200 210 102 83 3 121 78 93 258 56 44 165 215 71 209 9 157 238 259 182 295 38 90 217 316 278 203 277 97 88 302 193 22 116 122 230 236 7 268 7 242 115 3 95 186 125 238 285 74 263 12 224 187 264 164 50 299 159 127 127 153 45 13 33 121 91 39 242 89 111 173 166 37 314 20 188 53 307 162 148 122 204 27 85 294 190 1 167 117 248 164 63 245 97 114 194 161 42 250 92 132 122 217 290 69 281 257 280 118 37 36 175 94 60 191 94 47 245 110 60 178 148 109 258 43 98 227 228 4 247 12 237 133 248 151 117 261 110 47 232 164 76 191 81 101 261 123 310 216 197 143 153 32 67 49 134 24 31 245 123 6 162 135 176 220 40 18 286 239 35 62 106 217 303 15 265 244 30 126 34 273 280 105 91 52 188 27 98 240 174 305 234 79 199 84 168 256 128 292 288 141 212 17 206 259 208 187 277 110 34 286 226 89 124 119 150 24 18 299 185 19 95 173 179 300 252 7 255 61 304 82 253 133 235 205 179 274 43 85 281 244 17 180 50 286 213 143 140 86 83 16 67 62 80 8 64 312 131 3 82 240 187 251 218 112 266 92 119 176 233 303 2 2 306 43 59 26 5 314 46 80 21 10 296 118 24 44 191 107 39 229 143 127 140 99 29 54 129 42 276 301 100 142 34 260 17 167 104 302 180 76 178 135 163 274 56 31 219 231 84 142 1 206 272 154 171 264 177 42 237 146 194 135 150 11 72 44 152 269 87 222 259 195 241 293 77 284 7 229 169 19 108 119 163 287 2 15 252 298 46 93 284 311 283 185 32 41 157 212 4 260 4 221 120 315 113 114 181 215 58 263 25 170 171 251 231 58 250 79 186 138 184 223 61 13 20 175 107 6 175 81 114 207 107 26 283 159 140 73 137 78 80 312 118 11 98 253 120 289 221 146 207 81 88 315 139 6 149 189 192 233 290 56 18 273 293 51 75 39 255 35 49 160 233 316 265 257 293 64 21 23 242 102 57 111 199 58 276 288 154 158 1 193 9 170 184 197 169 45 41 183 104 289 234 92 145 68 155 6 136 243 208 203 ^ 656 0 221 48 21 32 186 40 42 178 159 51 196 72 161 187 177 283 306 23 266 309 296 129 10 26 220 172 316 178 61 228 151 130 205 90 34 297 168 69 109 182 112 292 299 83 192 46 269 263 159 149 19 117 63 143 274 67 292 201 260 147 104 313 126 56 163 200 123 225 16 90 230 262 258 232 21 57 39 264 296 31 147 300 278 216 219 35 75 50 197 13 78 225 237 267 185 41 302 95 197 71 220 270 139 223 3 144 288 273 191 228 28 135 295 253 265 172 95 1 106 130 107 267 29 36 212 291 6 196 293 19 142 275 8 209 239 280 131 23 291 162 161 64 142 14 150 254 141 236 268 126 277 21 155 221 309 198 306 284 124 264 75 173 192 242 234 34 3 21 253 44 35 140 262 62 227 250 213 167 30 50 99 150 33 4 281 170 82 55 124 141 40 263 36 114 109 280 294 18 201 39 289 149 215 82 153 306 186 301 219 133 257 95 99 248 175 9 183 126 179 198 110 279 34 101 163 298 265 270 237 46 8 86 204 51 294 214 206 89 133 61 130 9 85 303 134 256 154 182 210 115 25 304 108 143 53 209 18 103 176 244 247 299 304 10 1 8 307 62 6 73 258 69 305 147 202 136 171 277 119 297 266 211 154 84 68 70 83 29 11 67 71 24 305 49 60 91 269 2 22 194 280 33 160 246 260 245 286 39 68 12 260 24 109 84 289 247 38 127 55 222 283 85 205 311 211 252 226 113 12 39 166 154 305 245 25 181 113 233 216 121 212 30 148 241 195 254 239 59 313 28 233 118 298 167 128 192 144 92 308 101 65 156 220 49 281 268 224 100 66 57 137 87 22 292 103 78 102 202 38 29 232 177 22 129 68 168 265 74 272 275 204 174 10 124 43 217 218 134 158 12 137 308 199 247 201 162 5 59 52 210 278 20 214 304 271 178 282 46 106 228 249 312 250 311 309 75 271 15 287 136 269 100 164 239 182 308 297 70 246 64 240 196 195 156 97 14 52 112 96 15 312 29 134 35 17 227 152 71 122 128 94 2 47 47 145 287 13 274 190 8 111 97 235 229 67 194 59 215 205 188 216 23 70 25 206 285 98 151 293 240 230 66 253 142 177 185 164 18 5 34 199 26 24 207 226 15 189 313 224 198 208 102 79 3 119 76 89 256 56 40 165 213 69 207 5 157 234 255 180 295 32 88 217 316 276 203 273 93 86 302 193 20 116 122 226 236 7 268 3 242 111 318 93 184 125 238 281 72 259 10 222 185 262 160 50 295 155 123 127 153 45 9 27 121 89 35 238 85 107 169 166 31 310 16 188 53 307 160 148 118 200 25 83 290 188 314 165 115 246 162 63 241 97 112 194 157 38 250 90 132 120 213 290 65 279 255 278 118 37 30 173 94 60 189 92 47 243 110 58 176 146 105 254 43 94 223 224 2 243 12 235 131 244 149 117 259 108 45 230 164 76 187 79 101 261 109 ^ 656 0 310 208 189 143 149 32 59 41 130 20 31 245 123 2 154 135 168 216 32 14 286 231 31 62 102 213 303 7 257 244 22 118 26 269 272 105 91 44 180 27 94 232 166 301 230 79 199 84 164 248 128 288 284 133 208 17 198 259 204 187 273 102 30 282 218 85 116 111 146 16 18 299 177 11 87 169 179 292 252 3 255 53 296 82 249 125 227 201 171 266 39 77 273 240 9 172 46 278 205 139 136 86 79 16 63 54 76 56 312 123 312 78 236 179 247 210 104 266 84 119 172 229 299 315 311 298 31 51 26 314 314 38 80 13 2 292 114 24 44 191 103 27 221 135 123 140 99 25 317 54 121 42 276 301 92 134 22 256 5 159 100 298 180 72 170 131 155 270 52 23 219 231 76 138 1 202 272 150 167 264 169 30 237 142 186 127 142 3 72 32 152 265 87 214 255 191 241 293 77 284 316 229 161 15 100 115 159 283 319 3 244 298 42 93 280 303 283 181 24 33 149 204 4 252 313 213 120 307 113 106 181 207 54 259 21 166 163 251 223 50 246 75 186 138 184 223 61 1 8 175 107 6 167 81 114 207 99 14 275 155 132 73 133 70 72 308 110 11 98 245 112 281 221 146 199 73 88 315 139 319 141 189 188 225 286 48 10 273 285 51 71 35 247 27 49 156 233 312 261 257 289 64 17 15 238 94 49 111 191 58 272 288 146 154 318 189 5 170 176 197 169 41 313 41 175 96 285 234 92 145 64 155 315 128 243 208 200 219 48 21 28 184 40 40 178 157 47 196 68 157 185 175 279 306 23 264 307 296 127 4 24 216 170 314 176 59 224 151 130 203 86 34 295 164 65 107 178 112 292 297 79 188 42 265 259 159 145 19 113 61 139 274 65 290 199 256 143 104 311 126 52 161 198 121 225 10 90 230 262 254 228 15 55 39 260 294 29 147 300 278 216 215 35 75 48 193 7 74 223 233 267 185 37 300 95 195 71 218 268 137 221 318 144 284 271 187 228 26 131 293 249 263 172 91 320 104 128 105 263 23 36 210 287 194 291 13 140 271 4 207 237 280 131 17 291 162 161 60 142 14 148 252 141 234 264 124 275 17 153 217 305 198 304 280 120 262 71 173 192 238 232 28 1 19 251 40 29 136 258 58 227 246 213 165 28 46 95 150 29 319 279 168 78 53 124 137 38 263 34 112 109 276 290 16 201 33 287 149 215 80 151 302 182 297 217 133 253 93 97 248 173 9 183 122 177 194 108 279 30 99 163 296 265 270 235 44 8 82 204 49 294 212 202 89 129 57 126 7 85 299 132 256 154 180 210 115 21 304 108 141 51 209 14 103 176 242 245 295 302 10 318 6 305 60 4 69 258 69 303 145 202 134 171 277 115 297 262 209 152 82 66 70 83 29 9 67 67 22 301 47 58 89 267 2 16 190 278 33 160 246 258 241 282 35 64 6 260 18 105 80 289 247 38 125 55 292 ^ SHS Type 3 Strings 45 0 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 6 7 10 17 12 20 6 7 5 16 1 4 2 17 10 15 8 20 1 ^ SHS Type 1 Hashes DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 ^ 3CDF2936DA2FC556BFA533AB1EB59CE710AC80E5 ^ 19C1E2048FA7393CFBF2D310AD8209EC11D996E5 ^ CA775D8C80FAA6F87FA62BECA6CA6089D63B56E5 ^ 71AC973D0E4B50AE9E5043FF4D615381120A25A0 ^ A6B5B9F854CFB76701C3BDDBF374B3094EA49CBA ^ D87A0EE74E4B9AD72E6847C87BDEEB3D07844380 ^ 1976B8DD509FE66BF09C9A8D33534D4EF4F63BFD ^ 5A78F439B6DB845BB8A558E4CEB106CD7B7FF783 ^ F871BCE62436C1E280357416695EE2EF9B83695C ^ 62B243D1B780E1D31CF1BA2DE3F01C72AEEA0E47 ^ 1698994A273404848E56E7FDA4457B5900DE1342 ^ 056F4CDC02791DA7ED1EB2303314F7667518DEEF ^ 9FE2DA967BD8441EEA1C32DF68DDAA9DC1FC8E4B ^ 73A31777B4ACE9384EFA8BBEAD45C51A71ABA6DD ^ 3F9D7C4E2384EDDABFF5DD8A31E23DE3D03F42AC ^ 4814908F72B93FFD011135BEE347DE9A08DA838F ^ 0978374B67A412A3102C5AA0B10E1A6596FC68EB ^ 44AD6CB618BD935460D46D3F921D87B99AB91C1E ^ 02DC989AF265B09CF8485640842128DCF95E9F39 ^ 67507B8D497B35D6E99FC01976D73F54AECA75CF ^ 1EAE0373C1317CB60C36A42A867B716039D441F5 ^ 9C3834589E5BFFAC9F50950E0199B3EC2620BEC8 ^ 209F7ABC7F3B878EE46CDF3A1FBB9C21C3474F32 ^ 05FC054B00D97753A9B3E2DA8FBBA3EE808CEF22 ^ 0C4980EA3A46C757DFBFC5BAA38AC6C8E72DDCE7 ^ 96A460D2972D276928B69864445BEA353BDCFFD2 ^ F3EF04D8FA8C6FA9850F394A4554C080956FA64B ^ F2A31D875D1D7B30874D416C4D2EA6BAF0FFBAFE ^ F4942D3B9E9588DCFDC6312A84DF75D05F111C20 ^ 310207DF35B014E4676D30806FA34424813734DD ^ 4DA1955B2FA7C7E74E3F47D7360CE530BBF57CA3 ^ 74C4BC5B26FB4A08602D40CCEC6C6161B6C11478 ^ 0B103CE297338DFC7395F7715EE47539B556DDB6 ^ EFC72D99E3D2311CE14190C0B726BDC68F4B0821 ^ 660EDAC0A8F4CE33DA0D8DBAE597650E97687250 ^ FE0A55A988B3B93946A63EB36B23785A5E6EFC3E ^ 0CBDF2A5781C59F907513147A0DE3CC774B54BF3 ^ 663E40FEE5A44BFCB1C99EA5935A6B5BC9F583B0 ^ 00162134256952DD9AE6B51EFB159B35C3C138C7 ^ CEB88E4736E354416E2010FC1061B3B53B81664B ^ A6A2C4B6BCC41DDC67278F3DF4D8D0B9DD7784EF ^ C23D083CD8820B57800A869F5F261D45E02DC55D ^ E8AC31927B78DDEC41A31CA7A44EB7177165E7AB ^ E864EC5DBAB0F9FF6984AB6AD43A8C9B81CC9F9C ^ CFED6269069417A84D6DE2347220F4B858BCD530 ^ D9217BFB46C96348722C3783D29D4B1A3FEDA38C ^ DEC24E5554F79697218D317315FA986229CE3350 ^ 83A099DF7071437BA5495A5B0BFBFEFE1C0EF7F3 ^ AA3198E30891A83E33CE3BFA0587D86A197D4F80 ^ 9B6ACBEB4989CBEE7015C7D515A75672FFDE3442 ^ B021EB08A436B02658EAA7BA3C88D49F1219C035 ^ CAE36DAB8AEA29F62E0855D9CB3CD8E7D39094B1 ^ 02DE8BA699F3C1B0CB5AD89A01F2346E630459D7 ^ 88021458847DD39B4495368F7254941859FAD44B ^ 91A165295C666FE85C2ADBC5A10329DAF0CB81A0 ^ 4B31312EAF8B506811151A9DBD162961F7548C4B ^ 3FE70971B20558F7E9BAC303ED2BC14BDE659A62 ^ 93FB769D5BF49D6C563685954E2AECC024DC02D6 ^ BC8827C3E614D515E83DEA503989DEA4FDA6EA13 ^ E83868DBE4A389AB48E61CFC4ED894F32AE112AC ^ 55C95459CDE4B33791B4B2BCAAF840930AF3F3BD ^ 36BB0E2BA438A3E03214D9ED2B28A4D5C578FCAA ^ 3ACBF874199763EBA20F3789DFC59572ACA4CF33 ^ 86BE037C4D509C9202020767D860DAB039CADACE ^ 51B57D7080A87394EEC3EB2E0B242E553F2827C9 ^ 1EFBFA78866315CE6A71E457F3A750A38FACAB41 ^ 57D6CB41AEEC20236F365B3A490C61D0CFA39611 ^ C532CB64B4BA826372BCCF2B4B5793D5B88BB715 ^ 15833B5631032663E783686A209C6A2B47A1080E ^ D04F2043C96E10CD83B574B1E1C217052CD4A6B2 ^ E8882627C64DB743F7DB8B4413DD033FC63BEB20 ^ CD2D32286B8867BC124A0AF2236FC74BE3622199 ^ 019B70D745375091ED5C7B218445EC986D0F5A82 ^ E5FF5FEC1DADBAED02BF2DAD4026BE6A96B3F2AF ^ 6F4E23B3F2E2C068D13921FE4E5E053FFED4E146 ^ 25E179602A575C915067566FBA6DA930E97F8678 ^ 67DED0E68E235C8A523E051E86108EEB757EFBFD ^ AF78536EA83C822796745556D62A3EE82C7BE098 ^ 64D7AC52E47834BE72455F6C64325F9C358B610D ^ 9D4866BAA3639C13E541F250FFA3D8BC157A491F ^ 2E258811961D3EB876F30E7019241A01F9517BEC ^ 8E0EBC487146F83BC9077A1630E0FB3AB3C89E63 ^ CE8953741FFF3425D2311FBBF4AB481B669DEF70 ^ 789D1D2DAB52086BD90C0E137E2515ED9C6B59B5 ^ B76CE7472700DD68D6328B7AA8437FB051D15745 ^ F218669B596C5FFB0B1C14BD03C467FC873230A0 ^ 1FF3BDBE0D504CB0CDFAB17E6C37ABA6B3CFFDED ^ 2F3CBACBB14405A4652ED52793C1814FD8C4FCE0 ^ 982C8AB6CE164F481915AF59AAED9FFF2A391752 ^ 5CD92012D488A07ECE0E47901D0E083B6BD93E3F ^ 69603FEC02920851D4B3B8782E07B92BB2963009 ^ 3E90F76437B1EA44CF98A08D83EA24CECF6E6191 ^ 34C09F107C42D990EB4881D4BF2DDDCAB01563AE ^ 474BE0E5892EB2382109BFC5E3C8249A9283B03D ^ A04B4F75051786682483252438F6A75BF4705EC6 ^ BE88A6716083EB50ED9416719D6A247661299383 ^ C67E38717FEE1A5F65EC6C7C7C42AFC00CD37F04 ^ 959AC4082388E19E9BE5DE571C047EF10C174A8D ^ BAA7AA7B7753FA0ABDC4A541842B5D238D949F0A ^ 351394DCEBC08155D100FCD488578E6AE71D0E9C ^ AB8BE94C5AF60D9477EF1252D604E58E27B2A9EE ^ 3429EC74A695FDD3228F152564952308AFE0680A ^ 907FA46C029BC67EAA8E4F46E3C2A232F85BD122 ^ 2644C87D1FBBBC0FC8D65F64BCA2492DA15BAAE4 ^ 110A3EEB408756E2E81ABAF4C5DCD4D4C6AFCF6D ^ CD4FDC35FAC7E1ADB5DE40F47F256EF74D584959 ^ 8E6E273208AC256F9ECCF296F3F5A37BC8A0F9F7 ^ FE0606100BDBC268DB39B503E0FDFE3766185828 ^ 6C63C3E58047BCDB35A17F74EEBA4E9B14420809 ^ BCC2BD305F0BCDA8CF2D478EF9FE080486CB265F ^ CE5223FD3DD920A3B666481D5625B16457DCB5E8 ^ 948886776E42E4F5FAE1B2D0C906AC3759E3F8B0 ^ 4C12A51FCFE242F832E3D7329304B11B75161EFB ^ C54BDD2050504D92F551D378AD5FC72C9ED03932 ^ 8F53E8FA79EA09FD1B682AF5ED1515ECA965604C ^ 2D7E17F6294524CE78B33EAB72CDD08E5FF6E313 ^ 64582B4B57F782C9302BFE7D07F74AA176627A3A ^ 6D88795B71D3E386BBD1EB830FB9F161BA98869F ^ 86AD34A6463F12CEE6DE9596ABA72F0DF1397FD1 ^ 7EB46685A57C0D466152DC339C8122548C757ED1 ^ E7A98FB0692684054407CC221ABC60C199D6F52A ^ 34DF1306662206FD0A5FC2969A4BEEC4EB0197F7 ^ 56CF7EBF08D10F0CB9FE7EE3B63A5C3A02BCB450 ^ 3BAE5CB8226642088DA760A6F78B0CF8EDDEA9F1 ^ 6475DF681E061FA506672C27CBABFA9AA6DDFF62 ^ 79D81991FA4E4957C8062753439DBFD47BBB277D ^ BAE224477B20302E881F5249F52EC6C34DA8ECEF ^ EDE4DEB4293CFE4138C2C056B7C46FF821CC0ACC ^ SHS Type 2 Hashes A771FA5C812BD0C9596D869EC99E4F4AC988B13F ^ E99D566212BBBCEEE903946F6100C9C96039A8F4 ^ B48CE6B1D13903E3925AE0C88CB931388C013F9C ^ E647D5BAF670D4BF3AFC0A6B72A2424B0C64F194 ^ 65C1CD932A06B05CD0B43AFB3BC7891F6BCEF45C ^ 70FFAE353A5CD0F8A65A8B2746D0F16281B25EC7 ^ CC8221F2B829B8CF39646BF46888317C3EB378EA ^ 26ACCC2D6D51FF7BF3E5895588907765111BB69B ^ 01072915B8E868D9B28E759CF2BC1AEA4BB92165 ^ 3016115711D74236ADF0C371E47992F87A428598 ^ BF30417999C1368F008C1F19FECA4D18A5E1C3C9 ^ 62BA49087185F2742C26E1C1F4844112178BF673 ^ E1F6B9536F384DD3098285BBFD495A474140DC5A ^ B522DAE1D67726EBA7C4136D4E2F6D6D645AC43E ^ E9A021C3EB0B9F2C710554D4BF21B19F78E09478 ^ DF13573188F3BF705E697A3E1F580145F2183377 ^ 188835CFE52ECFA0C4135C2825F245DC29973970 ^ 41B615A34EE2CEC9D84A91B141CFAB115821950B ^ AB3DD6221D2AFE6613B815DA1C389EEC74AA0337 ^ 0706D414B4AA7FB4A9051AA70D6856A7264054FB ^ 3CBF8151F3A00B1D5A809CBB8C4F3135055A6BD1 ^ DA5D6A0319272BBCCEA63ACFA6799756FFDA6840 ^ FB4429C95F6277B346D3B389413758DFFFEEDC98 ^ 2C6E30D9C895B42DCCCFC84C906EC88C09B20DE1 ^ 3DE3189A5E19F225CDCE254DFF23DACD22C61363 ^ 93530A9BC9A817F6922518A73A1505C411D05DA2 ^ E31354345F832D31E05C1B842D405D4BD4588EC8 ^ 3FF76957E80B60CF74D015AD431FCA147B3AF232 ^ 34AE3B806BE143A84DCE82E4B830EB7D3D2BAC69 ^ D7447E53D66BB5E4C26E8B41F83EFD107BF4ADDA ^ 77DD2A4482705BC2E9DC96EC0A13395771AC850C ^ EAA1465DB1F59DE3F25EB8629602B568E693BB57 ^ 9329D5B40E0DC43AA25FED69A0FA9C211A948411 ^ E94C0B6AA62AA08C625FAF817DDF8F51EC645273 ^ 7FF02B909D82AD668E31E547E0FB66CB8E213771 ^ 5BB3570858FA1744123BAC2873B0BB9810F53FA1 ^ 905F43940B3591CE39D1145ACB1ECA80AB5E43CD ^ 336C79FBD82F33E490C577E3F791C3CBFE842AFF ^ 5C6D07A6B44F7A75A64F6CE592F3BAE91E022210 ^ 7E0D3E9D33127F4A30EB8D9C134A58409FA8695B ^ 9A5F50DFCFB19286206C229019F0ABF25283028C ^ DCA737E269F9D8626D488988C996E06B352C0708 ^ B8FFC1D4972FCE63241E0E77850AC46DDE75DBFA ^ E9C9BF41C8549354151B977003CE1D830BE667DB ^ 0942908960B54F96CB43452E583F4F9CB66E398A ^ FCE34051C34D4B81B85DDC4B543CDE8007E284B3 ^ 61E8916532503627F4024D13884640A46F1D61D4 ^ F008D5D7853B6A17B7466CD9E18BD135E520FAF4 ^ BD8D2E873CF659B5C77AAC1616827EF8A3B1A3B3 ^ B25A04DD425302ED211A1C2412D2410FA10C63B6 ^ A404E21588123E0893718B4B44E91414A785B91F ^ A1E13BC55BF6DAD83CF3AABDA3287AD68681EA64 ^ D5FD35FFABED6733C92365929DF0FB4CAE864D15 ^ C12E9C280EE9C079E0506FF89F9B20536E0A83EF ^ E22769DC00748A9BBD6C05BBC8E81F2CD1DC4E2D ^ F29835A93475740E888E8C14318F3CA45A3C8606 ^ 1A1D77C6D0F97C4B620FAA90F3F8644408E4B13D ^ 4EC84870E9BDD25F523C6DFB6EDD605052CA4EAA ^ D689513FED08B80C39B67371959BC4E3FECB0537 ^ C4FED58F209FC3C34AD19F86A6DACADC86C04D33 ^ 051888C6D00029C176DE792B84DECE2DC1C74B00 ^ 1A3540BEE05518505827954F58B751C475AEECE0 ^ DFA19180359D5A7A38E842F172359CAF4208FC05 ^ 7B0FA84EBBCFF7D7F4500F73D79660C4A3431B67 ^ 9E886081C9ACAAD0F97B10810D1DE6FCDCE6B5F4 ^ A4D46E4BA0AE4B012F75B1B50D0534D578AE9CB6 ^ 6342B199EE64C7B2C9CBCD4F2DCB65ACEF51516F ^ AABFD63688EB678357869130083E1B52F6EA861D ^ F732B7372DAF44801F81EFFE3108726239837936 ^ 5E9347FE4574CDCB80281ED092191199BADD7B42 ^ D5776B7DFFF75C1358ABDBBB3F27A20BB6CA7C55 ^ 022B7ADA472FB7A9DA9219621C9C5F563D3792F6 ^ 7F1DE4ECA20362DA624653D225A5B3F7964A9FF2 ^ CA0F2B1BFB4469C11ED006A994734F0F2F5EFD17 ^ 833D63F5C2EA0CD43EC15F2B9DD97FF12B030479 ^ 14FD356190416C00592B86FF7CA50B622F85593A ^ 4AB6B57EDDEF1CE935622F935C1619AE7C1667D6 ^ B456A6A968ACD66CAA974F96A9A916E700AA3C5D ^ FD1C257FE046B2A27E2F0CD55ED2DECA845F01D7 ^ 66E0D01780F1063E2929EAAD74826BC64060E38C ^ A8478DF406F179FD4EF97F4574D7F99EA1CE9EB8 ^ 248E58CF09A372114FC2F93B09C5FC14F3D0059E ^ F15767DE91796A6816977EFA4FCED4B7FD9B8A57 ^ 36A6BC5E680E15675D9696338C88B36248BBBAF4 ^ 4DEA6251B2A6DF017A8093AB066EE3863A4EC369 ^ D30E70E357D57E3D82CA554B8A3D58DFF528FA94 ^ 70CA84D827F7FD61446233F88CF2F990B0F3E2AA ^ 8D500C9CFDE0288530A2106B70BED39326C52C3C ^ F3D4D139EDFC24596377BC97A96FB7621F27FFC7 ^ 5509BAFFAC6D507860CEFC5AB5832CB63CD4B687 ^ 0C0AEA0C2FD7A620C77866B1A177481E26B4F592 ^ 149176007FEE58A591E3F00F8DB658B605F8390C ^ 17C0D7B0256159F3626786FFDB20237AE154FA84 ^ 741A58618ABEB1D983D67AFDCBC49AA397A3B8E0 ^ B738D6B3409EB9ED2F1719B84D13F7C36169CDEC ^ 3D33DE31F64055D3B128AC9A6AA3F92DFD4F5330 ^ B6925F4DF94949B8844C867428BA3DEDF4CF2B51 ^ CF5E7256292ABEC431D8E8B9CBEAF22AF072377E ^ 975DCE94902923977F129C0E4ACF40AD28DDB9AA ^ 333B0259B18CE64D6B52CF563DD3041E5F63A516 ^ SHS Type 3 Hashes 80E044703A880C20EC41F645120A8A5B5D194ECE ^ E142829CA08FC9787F17AA16CE727396169B2713 ^ 6A2BAF62469D311F9257A0727F52C7EAA87CCEB4 ^ 362E3E7136CA611D7FBF687D3BBDC54CDA64843F ^ F5900ADC6223A5D24A7526ABFC60FA8E2D59A5AB ^ AD0CAC6A21D5B10833DDE7FA85927D74EDA142A9 ^ 47AD337EAFFDC177AAF7CBD035BE6F398B9D0536 ^ 9CF58595DF80872535BCC7C056E223546F0BB4EE ^ 7151CEB1918278CED2902B1D663D596F8D1B986F ^ ADDC9F09AA4026EF6C4B7F1A84D3A13B4CDC65B3 ^ 921FE78A863A317B1FA1FB3CA3BE1948DE7EF754 ^ 64BE10732D71D52CE8A486DA23E6B453DF7C6FBD ^ 4A450659470DD759ABFAE1D73972A6D2E63AC16C ^ 0D665E4BBF30B7EAB955BDE84759E185EECAB4CB ^ 0C1B8EE94D61CDD0837EAED9FE33DE4A8334B596 ^ D93BFE2A6227A4BF9B7C61EBCE4A8CDE131593FE ^ BDA883F804B470C90BD6AC490DFC34EBC27F9648 ^ 46A0969373552213632591C52030C38E5DBDC49E ^ 4781289E48B910C550DC23CA7D3AF5324C03532D ^ 693A34CFCDDED0F3AC72E7197FCE9BB66A8E3981 ^ AE088AF1D8865140963B3ABFB63E32E04CD1506F ^ ADF0F8F1D85CA97586F5DC6DC5FD11FA39270F55 ^ E484F5AD86C5F4D09E366ADF6E0DE73449F97B28 ^ 81C49842BA3D7072FB42288E03CE737A2672C091 ^ F6CC71AD897C23A16835490DED289BFD45500AB0 ^ 23E71AED62FE8E28F34F58E7FE5594EC5EB0486C ^ 92BA7934AA5867EE52960F4E0EDFB90AA7B69305 ^ C3D1CC8CBD1B6FFEE0D90CE962CD9C09AB1548AA ^ 3CE37A583B71A6A77BE325066A0F00C5D11DFC3E ^ 76EF5D236E1042D356A3234A422C092F86003064 ^ 8C3F703436C6C882E60263540A8E4C3E5646DC15 ^ 6138F9F3AB43B988DD3857422CCB304352459F40 ^ B812DE98775B4690B4FC2ECFCAB61C73C7271DC7 ^ 06660985CD80D48E7B9F88455B4233924C3B64BB ^ 76AB4B6378D6F63499A94EB67EB1CB31AFF8D775 ^ F31F6B0BE7AB059A1F59A46481967E88392979E6 ^ 0C1638498FBB7DB9600B98B4B22EF85E0FE245FB ^ 5607C6AF600939736795AC523FA43B736F41A118 ^ 8A03244866BDD21B9D8A82E98436C894FAD86ECC ^ 8A75BFD911AF87303B9B8FB7A1A47CCA52D3D98A ^ 16F0F3B5D37411236A1E3D6B1EDAB74CDA25ED4B ^ AC72BF45477481F58A302628DC5299FFA32E7C9F ^ 74CFFD5881F75AC20726E1447DCF7F47024380EF ^ 5BFBECEECBC27DA05729C4D1AC8C1286EA6DCEC9 ^ 012AACBC0579FA4CB4F107E9A9AD1A86AD2F6A4D ^ F7D552CBC5EF90F1A579388B5A8A9EC71EB67681 ^ 10C70115C4C34753274BFED477DF01440A67A361 ^ 078D2FACD293B6B6219D89899C16AA1AA8E3DE82 ^ 83C6BF9FB0D3091ADF374EBFA0A69916F17E6D26 ^ 2CDB1924DA62AB64C007C6505FF657E4ADDEA9C1 ^ E95D209BCB9864B076FF4DFCA8F8BD75D62D1B48 ^ 632824CF5025F8F90AD2923BDDF449550D64C0F5 ^ 02B1C0B41FC27EC5A32E586F1AC480BF0061E56A ^ 28156BC6769AE390BF32C6512C46169181E1536D ^ F730E6E287D992E7F3E013B6F1E088F0B9C41598 ^ B056A6A832FA5FE964EF77FF3E0BE1C32E0D58C0 ^ D5B3D19AFBB48FB56BA6D44A82DE6BD08DB208DE ^ 0215AD79BD6B8023C05FD2F8966211897DF6337A ^ EC4CF38C244EB6526A44F70570925247145DA8CA ^ C0D931262ECE93DA5A6ABC89CD6AD3162EA6B09E ^ 6BB48FAC26AA2B4859BBDEFCFB53AE4D1D9A0340 ^ 58611D43741E67A7F0DA9CB337A59DCD1EBE758E ^ 7C2AEC216AF231509E47B7EED06BB17859812B7E ^ F60EE5DBF4A7A676EC98B3DDB1CDD6CDF3CDA33B ^ 0492E59B1F4C94E97F29A26C3EE7D57E1B0FDD72 ^ 4FCF549D902D9BE1101A756DB9E45415FB61BCD2 ^ 95C71D26AD6B38CC771376B4A4F962F12E1E3D4F ^ F6A2449E773C72FB886B3C43E2B30EC2A1B7454A ^ CDE86695E00AEC9A5DB6FDDB5D5A5934448D58E0 ^ 502318A758FABFF6AC53844E9E2BCD159C678510 ^ 589D295148F95F75DAE964DD743FE981FA236D4E ^ 7973DD33AE3599A556BACC77E8656E782E029EFF ^ 9F5BE43AADD43C6DB3883C9DA4B52E1A50257AEE ^ 454289D8FFB237A56D5214EAE88F0A9D328FEA1A ^ 7E686B36595BEB4C0D4528FF960EDB55088A028D ^ F9789D1EF19A0084AC0E9F43A4BC0EE0478939EF ^ 2F32B0E7CC8BE19C325545C816E77056D7BBE70F ^ 6B1617746F073CFCD2CEBCAFBBE6FD0E28ED2D56 ^ CF8D2EA3888AD76761799383E5A15979F6DB7A88 ^ 557AF6D9D5947203C60E98C9A79B92B8BD085E2B ^ C61A217423DE68ED6CD34C91756C8DD3A650A2A2 ^ 73F3F79C151B6C1BD9369EDB26B932C2362B0593 ^ 364141E5FBCDE83F210C5BBBEB6810F6299DE14B ^ F806BECD025D264FD59E93D9E3606A674C40F216 ^ E0C761A57F00CBFB07D49BCB034C36A7122F4C5B ^ 5D3831044B9E0032FBE3C3425FFD13698F413B33 ^ 7EB1AB41E9997753C5D530DF118E71E72D7B86FC ^ CC053EA1556269D7E8BCBA30B208FCBF0EE2EE64 ^ A57739B1DD41E7DC0C40D6B6159A7E73CE2748AA ^ 90DA527C9DB9ACC2FD530D560A2F1191A80D0567 ^ 6AC1F2A0B8CA0E5ABC9FDF1ADCE588FBDF5CC53E ^ 43C1A0A0EE4163EC929726989F92B03639B233AB ^ 8927F299462413AC29A74080E54D8EE2DB7165E7 ^ 0C8D7E22226D91B423E781B508F31517EAAB607B ^ 7286E20D7F08D18A893254FBD3CC833F7973DCAF ^ 0CB8C235928B8E936C43B8F29EF3758B9FD54A7B ^ F67C24CC23E440CA3F206CEEB5504ECA54CD5CA3 ^ D78A25DEAA1E7ADADDB3C145ED0E5263BA4F2910 ^ 00AA68174D29492C578AC853FFCD55908292D41A ^ D5570EEDB09A62A5948F7F311F7ED5EF247F9AD9 ^ SHS Type 1 Strings 0 1 ^ 1 1 1 ^ 2 1 1 1 ^ 3 0 1 1 1 ^ 2 0 2 2 ^ 4 1 1 1 2 1 ^ 3 0 2 2 2 ^ 4 1 1 2 2 2 ^ 5 1 2 2 1 1 2 ^ 5 0 2 2 1 1 3 ^ 4 0 3 3 3 1 ^ 5 0 2 2 3 2 2 ^ 5 1 2 3 3 1 3 ^ 5 0 3 3 3 2 2 ^ 6 0 2 3 1 2 3 3 ^ 7 1 3 3 3 1 1 1 3 ^ 7 0 2 3 1 2 3 2 3 ^ 6 1 2 4 3 3 3 2 ^ 7 0 2 4 3 3 1 1 4 ^ 8 0 2 3 1 1 2 2 4 4 ^ 7 0 2 4 2 3 1 4 4 ^ 9 0 4 1 2 1 1 2 4 4 2 ^ 8 1 4 4 1 1 4 2 2 4 ^ 7 0 3 3 4 3 4 4 2 ^ 11 0 1 3 1 1 2 1 2 4 4 4 1 ^ 6 0 4 3 4 5 5 4 ^ 7 1 2 5 2 4 5 4 4 ^ 12 1 1 2 3 3 1 1 1 4 2 1 5 3 ^ 11 0 2 3 3 3 1 2 2 4 1 5 2 ^ 8 1 3 3 5 5 2 5 2 4 ^ 9 1 5 4 5 1 2 1 5 3 4 ^ 9 1 5 1 5 2 3 4 4 4 3 ^ 12 1 1 2 5 1 1 5 5 1 4 1 5 1 ^ 12 1 5 3 2 1 3 2 2 2 1 4 5 3 ^ 10 0 5 1 4 5 5 4 1 1 3 5 ^ 12 1 1 5 2 3 1 5 1 3 3 5 1 5 ^ 12 0 1 1 2 3 2 5 1 3 3 6 4 5 ^ 11 1 3 1 5 1 3 4 3 1 5 5 6 ^ 8 1 4 6 4 5 4 4 5 6 ^ 10 1 6 5 4 3 3 3 2 6 2 5 ^ 10 1 2 3 4 4 5 5 2 5 6 4 ^ 13 1 3 1 3 1 4 1 6 6 5 1 2 6 2 ^ 10 1 4 3 3 6 6 6 3 2 6 3 ^ 13 0 3 5 3 1 4 1 4 3 5 3 4 1 6 ^ 10 0 2 5 5 2 6 6 5 2 6 5 ^ 12 1 2 2 5 3 6 6 4 3 2 4 3 5 ^ 13 1 2 6 3 6 5 2 3 2 1 2 3 5 6 ^ 13 1 3 5 6 2 1 1 6 2 4 5 4 5 3 ^ 16 1 2 1 4 3 2 3 2 5 3 4 1 4 1 5 3 5 ^ 11 1 3 1 3 6 7 7 4 1 6 5 6 ^ 12 0 2 5 2 7 5 5 4 2 2 6 7 3 ^ 13 1 6 4 4 1 4 2 5 2 4 2 7 4 6 ^ 12 1 3 4 7 6 7 1 4 4 3 2 5 6 ^ 16 0 3 2 4 5 6 1 1 1 5 3 4 1 4 4 5 4 ^ 14 1 5 1 3 7 6 3 1 3 7 3 1 5 7 2 ^ 14 0 1 5 3 2 7 1 5 5 4 6 5 3 6 2 ^ 14 0 4 7 6 6 2 3 5 1 1 3 6 2 3 7 ^ 13 1 6 4 6 3 7 5 1 4 5 1 7 4 4 ^ 13 0 7 5 3 1 4 7 4 2 2 7 5 4 7 ^ 15 1 7 3 6 1 1 2 7 5 1 5 4 6 1 6 4 ^ 16 0 2 5 3 2 7 2 3 5 2 1 3 3 3 7 5 7 ^ 18 1 3 7 2 4 1 7 3 4 1 5 1 5 1 1 6 1 2 7 ^ 17 0 2 1 7 3 7 1 2 1 4 3 6 6 6 2 2 5 4 ^ 22 1 2 2 1 1 2 6 2 4 1 1 3 5 2 3 4 5 6 1 1 2 6 3 ^ 12 1 7 8 7 2 1 3 5 7 8 7 4 5 ^ 15 1 3 5 5 2 2 2 7 4 2 8 7 4 5 5 4 ^ 16 0 1 4 4 6 1 2 7 1 6 4 1 8 4 7 4 6 ^ 16 0 8 7 7 2 5 2 1 5 6 1 1 5 1 5 6 5 ^ 14 0 7 3 2 3 8 3 3 8 2 8 3 7 7 4 ^ 14 0 4 2 6 5 4 5 3 8 8 4 8 2 6 4 ^ 14 0 8 7 1 3 5 8 2 8 1 4 5 2 8 8 ^ 16 0 5 5 2 2 4 2 4 7 6 1 5 8 3 8 7 2 ^ 16 0 1 6 6 6 6 4 2 2 6 4 2 4 4 6 7 6 ^ 16 1 2 3 7 4 1 7 7 5 7 2 4 7 2 6 6 3 ^ 13 0 7 4 8 6 5 7 6 3 5 7 5 8 3 ^ 16 1 4 1 1 5 4 3 6 5 5 8 5 4 8 5 3 8 ^ 13 0 7 4 4 5 8 3 8 3 8 6 6 6 8 ^ 14 1 5 4 7 5 8 4 6 1 6 2 7 8 6 8 ^ 18 1 3 4 4 5 3 4 1 6 3 7 6 7 3 3 2 8 4 5 ^ 19 0 5 8 1 2 1 3 5 3 1 6 6 3 7 4 5 7 1 4 7 ^ 17 0 5 7 7 2 2 6 4 7 1 7 8 1 5 3 2 7 6 ^ 14 0 9 3 6 9 3 4 7 6 9 1 7 2 9 6 ^ 21 1 8 6 5 2 2 4 3 1 1 6 2 8 4 2 5 4 5 1 2 5 6 ^ 16 1 2 6 5 4 9 8 1 8 1 7 6 7 7 1 2 9 ^ 15 0 6 9 5 4 7 1 7 3 9 4 7 7 5 2 8 ^ 16 0 1 7 8 2 7 2 9 8 8 3 4 5 2 4 8 7 ^ 16 1 1 6 8 2 8 1 6 7 7 5 9 2 9 2 8 5 ^ 16 0 4 2 9 6 2 6 6 7 9 9 1 9 4 1 5 7 ^ 18 1 6 9 2 7 2 8 5 8 4 3 4 4 6 6 3 1 6 4 ^ 19 0 1 7 4 4 4 6 1 6 3 9 5 6 4 7 2 2 5 5 8 ^ 17 1 8 5 3 7 3 5 6 4 1 9 2 6 5 7 9 1 9 ^ 18 0 8 8 6 3 5 3 3 5 5 3 8 3 2 5 5 4 7 8 ^ 16 1 4 7 7 2 7 3 8 5 7 5 6 8 5 2 8 8 ^ 19 0 3 7 2 3 9 5 9 7 7 6 5 3 1 1 5 2 3 9 6 ^ 18 0 2 4 6 7 8 1 2 9 7 2 3 5 8 9 1 7 9 4 ^ 21 1 4 1 8 3 3 1 7 3 5 7 4 1 8 3 6 3 5 7 6 8 2 ^ 17 0 4 8 3 7 9 8 6 8 4 2 8 7 2 4 4 5 7 ^ 18 1 3 9 7 1 4 5 6 9 2 9 1 3 8 4 7 8 7 4 ^ 25 1 2 4 8 1 7 2 7 5 5 3 2 3 2 1 2 1 1 2 4 2 8 7 8 7 4 ^ 25 0 9 4 6 5 8 1 1 1 3 2 1 3 1 1 1 5 3 3 6 5 7 4 5 6 8 ^ 19 1 7 5 6 6 8 2 4 1 8 7 1 6 3 4 8 5 8 5 6 ^ 19 0 6 1 2 1 7 1 10 7 4 5 1 6 4 6 8 7 10 9 6 ^ 16 0 10 10 5 5 9 7 2 5 4 3 6 3 10 10 5 8 ^ 18 1 2 3 5 9 8 5 10 6 8 4 2 2 4 7 9 6 9 4 ^ 18 0 5 10 3 1 4 5 4 6 8 3 7 7 7 5 9 2 9 9 ^ 18 1 4 9 7 5 4 4 10 6 9 3 6 6 8 6 2 4 6 6 ^ 17 0 5 7 4 8 5 9 10 4 9 1 4 8 6 6 5 9 6 ^ 17 1 3 4 8 9 1 5 8 10 5 10 3 8 1 6 8 9 9 ^ 18 0 8 3 6 1 3 10 3 7 6 5 9 3 10 9 4 6 10 5 ^ 16 1 9 1 9 6 5 7 7 10 9 6 1 5 7 10 8 9 ^ 20 0 6 4 10 10 4 3 9 8 10 3 3 5 2 1 8 1 3 2 9 9 ^ 17 1 10 6 10 6 8 3 6 7 3 10 8 6 6 4 4 9 5 ^ 19 1 9 4 3 4 7 3 8 10 2 4 10 7 6 10 1 3 5 7 9 ^ 21 1 2 2 2 3 9 2 8 3 9 3 7 7 4 9 9 5 4 2 6 10 7 ^ 17 1 5 9 8 8 9 10 9 1 8 3 10 2 7 2 10 4 9 ^ 23 0 5 4 10 4 10 7 8 3 1 1 3 4 2 1 1 10 2 1 4 10 10 10 4 ^ 19 0 9 2 5 7 9 6 7 1 8 9 1 2 1 10 8 10 4 7 10 ^ 22 1 2 6 8 8 9 7 2 1 3 3 10 6 2 6 2 6 5 2 5 10 5 9 ^ 22 1 8 7 8 10 1 6 3 7 4 5 5 5 1 9 2 2 5 5 2 10 9 4 ^ 21 0 1 10 2 6 10 9 4 3 3 7 10 2 9 6 10 2 1 5 6 3 10 ^ 21 1 8 5 7 10 5 6 7 3 3 1 2 9 4 8 6 3 9 1 7 7 9 ^ 22 0 5 5 6 5 2 3 5 3 11 4 5 1 10 6 4 11 8 3 6 5 6 7 ^ 20 0 2 1 9 9 3 6 1 8 11 6 7 11 6 1 10 6 7 5 5 8 ^ 19 0 4 1 7 10 4 8 10 8 10 4 11 9 6 1 4 5 6 11 4 ^ 19 1 9 2 4 11 11 11 7 1 1 6 8 1 9 8 5 11 5 4 10 ^ 20 0 8 3 10 1 7 6 10 8 2 9 3 8 6 8 9 3 7 5 1 11 ^ 22 0 4 5 8 4 10 6 5 4 5 3 3 4 1 5 9 4 10 9 6 7 3 11 ^ 21 0 6 5 8 7 8 11 2 1 11 10 3 3 2 9 1 3 6 9 10 10 2 ^ 24 1 3 1 1 9 4 2 5 7 3 10 11 5 6 7 1 7 7 8 7 2 2 7 4 9 ^ 23 1 9 4 6 3 7 5 10 9 8 9 3 2 1 7 2 2 7 6 2 8 3 6 10 ^ 22 1 7 10 2 10 5 1 8 7 7 3 8 6 6 8 3 2 11 6 3 4 7 6 ^ 20 1 11 3 7 2 10 10 7 5 2 4 3 5 11 3 11 8 9 5 5 10 ^ 19 0 6 2 6 8 5 9 4 9 10 9 8 3 2 10 11 2 6 11 11 ^ 20 1 8 2 4 2 7 3 9 9 11 8 2 11 4 8 4 8 10 6 9 8 ^ 21 0 6 10 10 7 9 2 5 11 9 10 7 3 1 4 5 4 10 1 2 8 10 ^ 18 1 8 11 6 10 8 9 11 6 7 7 2 6 2 6 10 6 9 11 ^ 21 0 5 11 1 6 8 11 8 10 5 10 3 7 8 9 9 1 1 1 10 2 10 ^ 25 1 5 10 2 9 9 9 7 2 2 4 6 1 11 7 3 3 5 5 2 11 2 5 5 10 2 ^ 21 1 1 8 1 11 6 9 3 6 11 7 11 8 6 9 4 4 10 7 1 8 7 ^ 23 1 7 7 5 11 1 4 7 11 11 11 9 2 1 3 8 2 8 7 4 5 2 5 8 ^ 24 1 4 11 5 10 7 7 9 5 1 5 6 2 9 1 5 7 9 9 11 1 1 3 1 11 ^ 27 1 10 4 6 8 5 7 11 4 10 8 6 4 3 4 4 2 1 1 3 3 1 11 2 3 4 10 6 ^ 21 1 7 11 2 7 10 10 9 10 1 3 10 4 3 11 10 2 5 3 9 11 4 ^ 22 0 7 9 10 9 5 2 6 6 9 2 7 4 9 8 4 9 2 5 9 8 10 3 ^ 21 0 12 2 6 12 7 9 3 5 11 6 11 3 5 4 4 11 10 2 1 10 10 ^ 27 1 1 4 12 2 10 1 6 5 5 4 1 10 3 1 12 3 2 11 5 1 4 6 4 6 11 11 4 ^ 22 1 8 9 4 8 12 5 5 9 3 5 2 3 4 12 12 8 5 3 1 9 10 9 ^ 24 0 5 12 8 6 2 4 11 11 2 7 11 9 4 5 2 1 8 3 10 2 5 2 8 9 ^ 21 0 3 7 7 7 5 9 11 5 9 11 2 9 7 5 6 11 2 12 4 9 7 ^ 26 0 4 4 6 4 7 2 4 2 5 7 2 6 11 5 9 8 2 5 10 2 10 8 8 5 2 11 ^ 23 1 3 3 2 6 9 10 5 6 8 5 8 11 3 6 10 4 6 9 2 11 10 3 10 ^ 25 1 1 3 12 3 7 4 5 5 3 8 9 2 4 8 7 7 9 1 9 11 4 5 7 7 10 ^ 20 1 11 9 8 10 11 1 7 12 6 7 4 2 12 12 2 3 9 10 8 8 ^ 20 0 12 11 1 4 10 6 10 3 9 7 12 4 11 8 4 6 12 4 7 12 ^ 24 0 8 6 4 8 2 2 9 2 9 6 3 6 3 3 10 12 2 7 8 7 8 12 10 7 ^ 26 0 5 11 11 7 3 3 9 10 3 9 3 3 7 2 9 9 1 2 4 12 2 5 5 6 10 4 ^ 22 1 12 9 10 10 12 12 7 8 2 7 1 6 8 2 8 7 6 3 1 1 12 12 ^ 22 1 11 10 2 11 10 8 1 2 8 12 8 3 9 5 7 9 8 7 11 1 10 4 ^ 22 0 10 1 8 6 12 2 11 7 10 4 10 6 5 7 10 11 3 3 8 8 4 12 ^ 26 0 8 5 5 12 1 8 6 7 6 11 8 10 4 3 7 6 1 5 1 1 9 1 5 8 9 12 ^ 21 0 1 12 4 11 12 9 2 12 12 3 12 5 4 12 4 1 5 8 12 9 10 ^ 26 1 5 3 8 1 11 4 7 3 3 10 4 9 6 6 4 3 9 11 1 3 7 10 7 9 6 11 ^ 23 0 7 12 3 5 8 9 7 10 8 11 10 11 6 1 8 1 1 6 3 9 8 12 6 ^ 25 0 1 5 5 6 5 12 1 1 1 11 9 9 3 11 9 6 1 11 3 1 12 8 11 11 10 ^ 22 1 10 9 7 3 10 2 6 4 11 3 11 6 4 5 5 11 12 9 7 8 12 9 ^ 22 0 8 5 10 7 12 8 3 4 4 5 8 9 12 6 8 10 6 7 11 4 8 10 ^ 26 0 3 5 3 11 11 2 1 9 1 10 4 4 6 9 4 7 6 5 10 10 1 8 9 9 6 12 ^ 24 0 12 11 4 10 1 3 7 5 11 9 11 7 2 11 5 4 7 8 1 6 12 7 4 9 ^ 28 0 1 12 10 2 2 2 4 9 11 4 11 7 2 4 3 11 7 10 5 10 5 5 3 5 2 7 5 9 ^ 26 1 4 1 4 2 13 6 11 5 6 8 5 1 5 6 3 8 1 5 8 9 9 10 12 13 12 2 ^ 26 0 12 3 1 11 2 12 6 8 6 8 11 4 11 10 9 6 3 3 2 2 2 13 2 1 13 9 ^ 22 0 3 3 12 13 13 7 12 2 8 11 9 10 10 1 1 13 11 13 4 1 11 3 ^ 26 1 2 6 2 8 12 3 7 12 8 9 8 3 12 7 4 9 2 6 4 9 9 4 8 2 4 12 ^ 24 1 8 11 11 3 13 2 10 3 10 8 6 6 4 4 13 4 2 4 8 1 11 12 9 10 ^ 29 1 1 2 5 1 1 10 3 2 4 9 11 8 2 5 2 8 10 2 10 11 7 8 12 6 1 9 8 4 12 ^ 23 0 6 12 7 10 7 7 13 2 2 7 10 2 8 13 10 7 11 2 5 9 11 13 1 ^ 25 1 3 11 2 10 5 11 5 7 10 8 10 1 10 3 11 7 9 5 3 3 4 5 13 12 8 ^ 26 1 5 13 9 4 3 3 4 3 13 1 6 11 10 8 13 3 4 11 9 1 9 1 7 8 7 11 ^ 22 1 1 3 13 8 11 3 4 10 10 12 7 2 11 4 7 7 6 13 13 9 13 11 ^ 26 1 7 9 7 8 9 9 5 1 13 3 3 4 9 2 1 8 9 3 9 12 8 10 10 6 11 3 ^ 23 1 3 8 12 8 10 4 3 8 5 5 7 11 13 11 12 11 4 12 3 6 5 11 8 ^ 27 0 3 10 9 6 9 7 2 10 4 4 5 5 2 12 13 5 3 1 10 1 4 7 8 13 13 12 3 ^ 30 0 2 6 5 4 7 3 10 6 13 6 3 9 6 2 10 5 3 8 4 1 11 3 5 3 7 11 1 12 9 7 ^ 29 0 5 2 13 6 5 2 6 3 2 9 5 3 6 6 4 10 2 4 7 7 10 13 9 6 10 6 5 9 8 ^ 31 1 9 8 2 7 3 5 11 3 7 7 5 6 2 1 1 6 2 11 5 4 5 7 9 1 11 10 2 3 9 12 10 ^ 28 0 11 1 4 1 12 10 5 5 1 7 2 3 10 7 12 9 2 8 2 6 10 5 12 12 4 9 2 13 ^ 26 1 11 9 8 12 4 12 7 3 4 4 6 1 2 7 12 4 6 8 10 11 11 1 10 2 9 12 ^ 28 0 10 9 7 10 1 10 9 12 7 10 7 6 6 5 3 2 3 1 3 12 1 4 13 3 9 7 9 8 ^ 27 1 4 11 1 5 6 9 12 12 13 13 13 1 2 13 1 2 1 12 12 3 2 2 8 3 13 7 7 ^ 29 0 6 5 5 2 4 2 11 4 4 13 9 13 7 3 12 8 3 7 6 4 12 3 1 8 11 1 6 13 6 ^ 23 1 11 6 6 11 7 13 11 6 7 4 4 12 2 13 5 12 5 7 9 6 11 11 11 ^ 23 0 11 13 11 7 4 3 6 12 13 10 11 5 12 13 11 6 1 1 4 7 13 10 7 ^ 27 1 7 5 13 5 4 8 7 3 9 6 7 11 7 1 9 3 8 5 8 8 2 13 13 8 5 13 4 ^ 30 1 2 5 8 4 13 10 6 4 2 6 1 1 12 4 13 5 10 4 10 8 5 7 1 5 5 12 4 8 6 12 ^ 28 1 12 1 12 11 10 2 3 10 1 2 6 11 12 9 11 12 2 1 9 4 1 5 7 2 12 11 4 11 ^ 29 0 6 8 7 8 8 12 2 7 4 12 11 5 5 3 5 13 4 11 8 8 9 2 2 1 6 2 8 6 12 ^ 28 1 7 13 5 7 11 3 1 9 2 5 12 8 6 2 5 9 10 10 11 4 5 12 5 4 6 5 6 13 ^ 25 1 14 4 8 2 9 11 7 4 3 2 8 14 6 14 7 13 5 5 14 6 5 11 6 6 13 ^ 26 1 3 5 12 1 11 13 1 3 3 10 11 5 6 12 11 12 7 14 4 3 6 6 10 11 14 4 ^ 27 0 4 2 3 10 7 12 13 8 8 12 10 13 1 7 10 2 7 2 13 10 2 3 3 6 4 13 14 ^ 24 1 11 1 9 14 4 14 14 8 10 13 4 3 2 7 6 6 8 14 5 11 7 14 14 1 ^ 22 1 13 13 10 9 13 8 14 9 3 14 3 11 9 9 12 13 2 10 1 5 8 12 ^ 25 0 9 10 9 8 4 14 6 9 3 13 10 11 3 1 4 6 10 3 4 3 12 12 14 11 13 ^ 26 1 11 8 11 7 8 10 9 12 11 6 10 6 3 9 9 1 7 5 6 7 7 12 4 5 8 11 ^ 26 1 12 10 8 14 7 4 13 13 8 4 5 3 2 4 7 14 3 10 6 9 13 9 2 1 9 14 ^ 28 0 6 12 2 4 7 8 11 10 12 2 14 3 1 1 1 12 5 13 9 12 5 9 10 5 1 12 10 8 ^ 29 1 2 6 5 14 14 3 6 13 1 2 6 2 12 1 2 10 1 4 5 14 10 12 11 2 3 14 14 12 5 ^ 30 1 5 2 3 5 11 12 3 7 12 7 9 8 3 3 14 10 5 2 9 3 8 6 11 8 7 8 1 6 12 7 ^ 28 1 14 5 2 14 7 8 1 5 4 12 9 6 12 1 1 7 9 5 14 11 9 4 1 10 1 14 10 12 ^ 27 0 7 2 8 5 3 14 8 9 4 6 11 3 11 6 12 1 7 14 9 14 6 10 6 1 8 14 10 ^ 26 1 6 14 2 2 12 10 5 10 10 8 3 7 13 10 1 14 1 14 7 11 12 9 1 8 8 12 ^ 30 0 6 13 5 13 3 5 8 8 8 2 5 5 4 2 13 14 7 2 12 12 3 3 5 7 5 11 3 7 13 7 ^ 26 0 13 7 2 8 4 10 14 2 7 1 10 8 11 11 2 13 9 11 2 9 11 7 13 11 2 14 ^ 31 1 7 7 8 5 13 4 1 12 14 1 9 11 3 5 3 13 11 7 3 2 9 1 3 13 6 3 10 12 1 13 3 ^ 23 0 9 8 8 7 14 13 6 13 14 12 13 12 7 4 14 10 1 3 9 7 11 14 5 ^ 27 1 1 10 4 12 4 11 5 13 13 4 12 13 7 12 12 4 13 6 2 7 5 2 8 7 13 12 3 ^ 26 1 7 6 11 12 14 12 3 12 8 7 4 9 14 1 8 11 6 5 10 10 6 8 5 2 11 14 ^ 33 1 1 11 1 5 3 8 1 12 14 5 1 3 7 2 3 9 3 4 14 4 4 10 8 5 14 1 11 12 12 10 4 13 2 ^ 32 0 11 4 4 9 5 5 8 9 5 10 4 2 4 7 9 9 6 3 5 1 8 3 2 13 3 14 9 8 9 10 14 5 ^ 28 0 12 9 5 8 7 2 14 12 3 8 14 6 6 4 7 5 7 10 7 11 10 1 9 6 7 12 8 9 ^ 25 0 9 9 2 11 13 12 11 11 6 14 13 10 5 6 8 10 4 3 11 11 14 5 5 10 7 ^ 30 0 13 9 14 11 4 8 12 9 5 9 1 2 9 13 12 6 1 14 11 10 7 8 6 1 4 3 2 2 2 13 ^ 33 1 13 5 9 6 13 9 1 13 2 6 8 9 1 3 12 13 3 4 4 12 5 2 1 12 1 6 2 1 8 2 14 13 9 ^ 32 1 8 6 7 1 4 4 6 1 13 3 3 1 13 7 6 11 6 4 9 10 4 8 13 1 9 10 12 7 10 11 10 5 ^ 30 0 12 6 6 3 4 13 1 4 11 10 2 6 14 6 9 12 6 2 2 11 9 13 4 7 9 14 2 11 8 7 ^ 26 1 2 11 13 2 9 11 8 11 11 15 13 13 3 15 2 12 1 15 3 8 4 9 13 1 13 7 ^ 32 1 9 6 1 2 2 1 15 3 15 1 10 1 4 11 14 14 6 10 2 5 9 10 10 9 1 2 14 10 12 1 1 15 ^ 29 1 13 2 3 8 12 5 14 9 8 9 2 14 1 4 6 15 10 9 2 7 9 4 8 7 9 10 11 11 5 ^ 34 1 12 2 7 2 12 8 2 8 6 3 12 4 4 10 1 14 12 11 5 15 3 3 3 14 13 2 2 3 8 2 1 8 8 8 ^ 31 0 6 2 7 10 1 13 10 6 6 6 2 8 7 6 7 14 3 12 6 8 9 3 11 1 3 10 12 11 11 9 9 ^ 24 1 13 15 4 7 11 13 10 14 14 13 4 11 5 6 11 8 12 13 9 1 10 9 10 7 ^ 33 0 3 1 3 3 4 13 1 6 14 8 3 4 3 2 1 14 14 14 5 13 13 11 10 13 4 3 10 11 3 6 1 10 7 ^ 28 0 7 9 13 9 15 2 4 12 10 10 4 12 3 8 5 6 13 1 6 15 1 8 9 6 12 11 7 14 ^ 32 1 3 1 13 6 4 1 9 4 5 7 1 8 8 11 10 5 15 14 2 8 14 9 7 12 2 4 13 7 4 3 9 14 ^ 31 1 14 12 13 8 4 12 2 6 5 12 9 3 11 8 5 13 5 10 5 2 3 7 12 14 4 1 7 3 6 9 9 ^ 32 1 10 15 7 2 13 5 7 2 5 2 10 7 11 5 5 9 8 2 9 3 3 6 3 13 10 3 5 7 15 11 10 12 ^ 38 0 2 3 7 1 6 3 3 12 5 2 9 4 5 11 2 1 7 6 14 7 14 10 4 11 6 3 11 2 10 6 4 8 1 4 9 4 15 4 ^ 27 0 7 7 4 14 2 3 14 15 10 7 12 7 5 8 7 15 15 14 10 2 3 1 10 12 15 9 9 ^ 31 1 15 3 9 9 5 4 2 6 14 4 9 5 12 8 1 6 1 4 8 7 10 14 3 10 14 8 11 9 8 10 9 ^ 28 0 14 11 8 3 5 5 7 2 11 4 4 4 6 14 13 10 14 10 3 9 6 9 7 5 10 15 15 15 ^ 30 1 8 13 4 2 13 6 4 7 4 4 15 2 2 12 13 3 14 12 7 11 6 2 14 2 6 6 9 14 13 12 ^ 27 1 13 14 15 12 14 5 14 15 11 4 1 1 9 5 13 10 6 5 5 6 14 13 1 5 3 14 13 ^ 29 0 4 2 13 12 15 7 3 15 5 1 6 7 6 13 1 14 11 9 5 15 6 13 3 6 11 7 15 8 9 ^ 31 0 5 4 4 14 3 13 8 13 3 7 13 7 9 12 3 11 15 11 5 14 1 3 4 10 12 7 12 1 2 13 4 ^ 28 1 12 7 13 14 7 7 1 9 13 8 5 14 2 5 9 9 15 9 13 7 8 9 8 1 12 3 9 15 ^ 34 1 6 12 4 14 12 5 3 15 4 4 6 8 2 11 8 4 2 5 1 15 15 1 15 2 11 4 10 9 4 7 3 2 15 6 ^ 26 0 14 5 6 5 11 12 14 12 12 11 15 2 14 9 15 1 7 12 11 12 13 14 1 1 12 5 ^ 32 0 2 2 4 5 2 11 12 5 4 12 9 14 5 5 8 6 2 15 15 6 13 11 3 5 15 5 11 3 12 7 10 8 ^ 26 1 2 15 14 9 14 7 6 15 9 3 4 8 8 12 14 2 9 11 14 6 11 15 10 8 14 8 ^ 34 1 15 7 4 5 10 1 13 7 1 1 8 3 13 11 2 8 15 11 12 6 6 1 3 2 2 11 3 13 9 10 3 6 12 15 ^ 25 0 15 7 10 2 10 15 5 10 13 12 8 15 3 1 11 14 15 8 15 12 9 6 8 13 13 ^ 27 0 10 8 13 10 15 13 5 8 4 10 10 6 7 13 6 12 12 9 12 2 5 10 12 10 8 15 6 ^ 28 0 5 3 8 12 15 8 14 15 9 12 12 3 10 13 6 11 10 4 13 14 8 9 1 8 1 5 11 12 ^ 29 0 9 12 4 13 15 5 9 11 7 14 11 1 11 7 8 8 11 1 13 15 12 1 5 8 3 8 10 7 14 ^ 30 0 1 5 13 12 14 5 3 6 4 12 15 6 6 10 11 13 9 1 11 6 10 3 7 14 4 14 11 7 8 13 ^ 34 1 1 12 5 1 7 4 6 7 5 11 1 4 7 12 10 10 8 15 13 4 11 15 11 6 9 1 2 15 5 1 5 12 6 13 ^ 35 1 12 15 4 11 13 3 6 5 10 8 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 15 1 12 4 4 2 15 4 ^ 27 0 15 11 15 5 11 9 7 15 16 6 16 12 3 2 10 16 5 5 7 1 7 11 13 7 9 11 12 ^ 31 1 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 3 3 6 7 16 7 6 15 5 8 15 6 15 ^ 30 1 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 8 16 2 12 16 10 14 7 ^ 36 1 2 3 7 14 6 9 4 4 5 9 7 12 3 9 2 5 1 3 10 11 11 6 12 7 1 7 12 2 1 2 8 12 15 16 9 13 ^ 34 1 6 3 12 11 16 15 8 8 8 14 13 7 7 8 2 7 6 2 2 14 7 1 4 2 4 11 11 5 7 2 12 1 14 11 ^ 29 0 12 11 2 9 8 5 6 14 10 12 5 11 5 3 1 13 15 9 12 11 13 4 14 5 16 3 5 13 15 ^ 30 1 5 16 11 2 6 13 16 3 6 4 9 10 9 8 6 14 8 9 5 13 6 5 14 2 8 15 8 7 14 11 ^ 28 1 14 10 13 13 11 10 13 9 8 4 11 14 11 6 10 10 1 9 13 16 5 3 4 7 9 12 10 8 ^ 36 1 10 15 12 8 8 10 13 5 6 11 4 6 2 3 5 6 11 1 1 8 6 13 15 6 3 15 5 10 1 6 2 5 2 11 10 10 ^ 31 1 4 14 7 2 14 3 1 12 7 15 13 1 5 9 8 3 3 14 12 13 2 15 12 7 16 12 3 8 11 5 15 ^ 34 0 10 2 10 16 4 16 7 8 1 16 6 14 9 5 12 16 8 9 4 4 4 1 7 13 10 1 7 10 5 7 4 1 5 15 ^ 30 0 16 3 8 7 3 8 8 11 8 13 4 16 8 16 1 4 16 11 4 12 1 14 5 1 16 11 8 14 12 9 ^ 33 0 7 9 9 16 11 7 6 1 11 14 12 14 10 9 11 8 11 7 5 10 15 2 6 9 3 9 4 2 1 1 9 14 6 ^ 32 0 5 8 14 15 4 1 6 1 10 8 1 15 15 3 10 7 8 10 12 4 3 11 15 8 5 3 3 16 15 7 14 13 ^ 36 0 3 10 12 2 11 9 2 1 4 3 8 10 14 2 11 3 2 4 15 14 5 2 8 16 16 1 5 7 5 9 5 15 9 11 3 14 ^ 31 1 5 4 14 4 8 3 3 1 10 4 15 15 13 2 13 9 7 13 11 9 1 15 15 15 16 7 7 6 5 13 9 ^ 30 0 14 16 12 1 11 11 7 3 7 3 3 13 4 13 14 5 15 12 5 14 16 14 4 5 9 6 6 3 16 11 ^ 28 1 10 16 10 14 13 6 16 14 3 14 15 7 13 12 4 1 8 4 10 6 1 13 6 14 11 3 16 14 ^ 33 0 15 11 13 8 11 1 15 2 10 9 9 14 8 13 2 13 8 1 2 1 3 12 8 5 4 11 10 14 8 9 4 5 16 ^ 34 1 12 12 6 7 13 13 12 1 13 14 1 1 6 3 13 2 16 3 1 16 9 9 15 3 13 1 8 3 2 6 12 8 9 13 ^ 27 0 11 12 15 14 12 10 8 15 9 15 2 7 5 11 8 9 7 16 6 15 4 15 7 11 15 4 14 ^ 29 1 9 1 14 7 4 14 16 11 10 11 12 14 6 12 11 15 7 14 3 15 6 1 12 5 12 13 3 6 14 ^ 28 0 6 10 7 7 9 10 7 11 12 16 9 6 9 14 10 10 2 7 4 15 16 13 11 8 10 15 10 15 ^ 32 1 8 12 1 10 3 7 15 14 9 16 14 1 15 3 14 9 2 2 12 14 7 3 5 14 5 15 10 2 14 1 15 8 ^ 33 0 9 16 10 16 6 13 1 6 2 8 13 5 7 2 15 11 12 6 8 7 1 5 8 13 9 4 8 12 9 15 1 10 13 ^ 30 0 10 4 16 4 13 12 2 4 14 6 11 3 15 8 4 12 3 11 16 16 16 2 13 7 10 2 13 10 15 10 ^ 33 1 16 2 15 10 4 1 13 12 12 9 12 7 16 4 12 4 2 16 4 9 16 8 2 6 15 2 3 4 9 12 6 8 12 ^ 34 1 13 11 11 4 9 13 14 2 9 6 8 6 10 11 9 3 12 9 13 4 10 3 5 1 14 11 11 16 1 2 2 11 6 14 ^ 33 1 15 12 6 5 16 2 14 2 10 12 2 5 5 6 10 13 12 3 10 8 16 9 5 12 15 4 11 13 3 6 5 10 8 ^ 35 1 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 15 1 12 4 4 2 15 13 15 11 15 5 11 9 7 15 16 4 ^ 36 0 16 12 3 2 10 16 5 5 7 1 7 11 13 7 9 11 2 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 4 ^ 35 0 3 6 7 16 7 6 15 5 8 15 6 4 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 16 ^ 31 0 7 4 8 17 16 16 11 14 2 10 14 15 10 9 1 14 10 14 6 6 16 3 2 3 8 3 12 8 11 17 2 ^ 30 1 9 7 16 14 4 11 15 5 13 9 5 12 17 17 13 8 2 6 8 16 1 12 5 17 2 9 8 10 13 6 ^ 27 0 11 17 12 5 14 9 11 9 11 4 11 13 16 6 10 5 8 3 17 16 14 1 15 15 15 6 17 ^ 29 1 2 11 6 13 11 13 4 6 7 11 11 12 16 13 1 16 16 14 16 2 4 16 11 6 15 7 4 17 11 ^ 32 0 5 7 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 17 5 4 8 14 3 16 7 13 4 14 8 9 17 ^ 31 1 8 12 8 15 9 6 6 1 5 13 16 5 8 4 6 10 6 11 16 17 15 15 12 4 13 5 3 4 10 15 16 ^ 33 0 7 15 16 12 12 11 8 13 14 5 8 1 11 10 9 3 14 3 1 9 6 15 12 16 4 5 9 7 1 9 4 8 17 ^ 36 1 7 9 16 11 11 6 13 7 1 7 8 1 14 12 2 7 4 5 15 16 12 3 1 6 11 4 15 8 9 9 2 1 13 2 14 14 ^ 29 1 6 8 8 15 13 13 10 2 16 12 17 6 7 14 13 12 13 3 14 12 12 2 15 2 5 15 10 7 15 ^ 38 1 5 15 7 8 10 10 1 11 2 4 3 11 11 3 5 2 3 11 5 12 12 8 6 2 17 15 6 16 15 4 3 14 6 3 2 10 5 15 ^ 30 0 12 11 15 14 2 16 14 7 6 15 9 3 11 8 8 5 16 2 16 2 16 6 9 6 12 10 16 7 15 10 ^ 36 0 11 5 3 16 1 15 7 10 17 10 10 13 2 2 17 6 2 5 6 6 10 12 2 9 11 12 6 1 1 8 12 2 6 16 12 16 ^ 30 1 10 17 5 1 6 14 17 8 12 10 11 16 15 1 8 3 9 13 7 7 16 8 13 11 10 8 15 3 15 12 ^ 31 1 14 8 4 12 1 6 5 13 15 3 5 11 14 11 14 17 5 10 17 7 8 13 5 12 15 3 6 17 7 17 7 ^ 31 0 12 3 10 10 4 13 13 8 11 13 7 17 11 1 10 1 5 11 11 9 14 13 15 8 14 2 7 16 11 8 15 ^ 32 1 7 16 17 17 4 1 13 15 5 1 5 6 14 15 1 5 1 9 9 17 12 13 12 7 12 3 7 15 4 16 12 13 ^ 36 0 8 17 1 11 4 10 2 6 10 3 16 16 2 7 13 9 15 7 17 14 3 10 16 13 6 7 5 2 1 4 16 3 10 1 15 5 ^ 32 0 4 6 4 15 11 4 2 17 9 15 5 10 7 12 15 16 15 17 12 14 9 2 13 4 9 2 4 15 2 11 9 16 ^ 29 0 4 4 3 17 2 14 17 17 1 17 13 11 15 17 4 9 15 8 11 16 9 10 8 9 12 15 1 17 11 ^ 35 0 16 4 2 14 14 15 1 2 12 9 1 10 16 10 11 7 1 12 17 8 2 15 11 1 7 17 12 7 3 7 6 9 9 14 6 ^ 36 0 2 15 17 10 11 9 5 9 4 17 16 3 11 2 10 12 11 5 3 8 17 15 3 3 4 7 2 1 10 7 14 4 16 6 12 8 ^ 36 1 12 14 6 9 3 17 11 10 6 8 14 6 11 7 10 8 6 17 4 4 9 8 2 8 14 8 7 14 1 3 6 8 11 10 17 1 ^ 39 1 12 14 9 4 11 7 6 6 13 14 2 13 1 14 9 7 7 15 2 2 5 15 13 17 3 15 16 9 1 1 2 3 2 12 1 3 3 13 9 ^ 34 0 13 10 15 5 8 10 15 10 8 7 5 5 14 4 13 11 12 4 4 12 10 13 12 4 10 3 3 7 9 13 16 9 17 1 ^ 36 0 4 12 1 9 12 13 5 10 1 3 15 4 1 13 17 1 8 9 6 12 4 7 7 10 17 13 17 6 17 9 6 9 3 5 17 10 ^ 34 0 1 4 10 12 17 14 11 8 5 16 5 5 2 13 13 16 9 13 10 9 9 5 3 13 6 4 3 9 15 14 14 7 3 16 ^ 38 1 9 17 3 6 5 16 10 14 9 1 16 7 3 5 4 17 14 7 12 6 2 8 8 17 7 2 4 5 7 12 2 1 7 11 3 14 9 15 ^ 41 0 2 12 3 4 1 4 1 16 10 5 16 8 7 2 10 3 5 9 16 8 16 13 3 12 5 5 11 2 2 7 4 2 8 16 4 14 5 14 10 4 17 ^ 36 0 6 1 2 7 1 15 13 1 17 4 7 4 8 17 16 16 11 14 2 10 14 15 10 9 1 14 10 14 6 6 16 3 2 3 8 14 ^ 32 1 12 8 11 17 3 9 7 16 14 4 11 15 5 13 9 5 12 17 17 13 8 2 6 8 16 1 12 5 17 2 9 14 ^ 29 0 10 13 14 11 17 12 5 14 9 11 9 11 4 11 13 16 6 10 5 8 3 17 16 14 1 15 15 15 14 ^ 32 0 13 2 11 6 13 11 13 4 6 7 11 11 12 16 13 1 16 16 14 16 2 4 16 11 6 15 7 4 17 6 5 15 ^ 35 1 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 17 5 4 8 14 3 16 7 13 4 14 8 9 3 8 12 8 15 11 ^ 33 1 6 6 1 5 13 16 5 8 4 6 10 6 11 16 17 15 15 12 4 13 5 3 4 10 15 12 7 15 16 12 12 11 11 ^ 40 0 13 14 5 8 1 11 10 9 3 14 3 1 9 6 15 12 16 4 5 9 7 1 9 4 8 5 7 9 16 11 11 6 13 7 1 7 8 1 14 10 ^ 34 0 2 10 15 10 14 8 18 9 9 12 12 3 13 12 6 4 9 17 13 13 5 7 3 2 1 17 14 4 16 6 13 1 13 13 ^ 35 1 6 10 1 3 18 3 11 7 9 5 7 11 17 1 9 16 5 15 10 17 3 8 15 17 8 15 11 3 15 17 11 1 1 4 15 ^ 36 1 14 18 4 2 18 8 15 6 4 6 3 15 11 16 10 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 3 2 12 2 14 16 ^ 37 0 4 1 5 11 16 18 16 8 11 15 2 18 7 5 14 5 15 13 3 3 5 4 3 11 4 4 5 10 3 12 17 1 4 17 10 10 17 ^ 35 0 1 3 4 2 1 12 5 14 11 10 4 6 14 9 1 5 8 2 9 15 12 13 7 16 2 13 17 15 9 18 15 9 13 16 17 ^ 34 1 18 10 4 11 13 9 6 1 17 6 8 6 5 11 5 14 16 9 13 11 10 9 15 4 14 7 14 3 1 15 5 5 18 16 ^ 34 0 13 8 13 16 5 17 5 10 1 8 8 12 6 13 18 9 6 17 3 16 2 8 9 8 7 2 14 14 8 10 13 9 11 11 ^ 40 0 7 11 4 6 9 10 11 12 2 14 1 13 1 7 1 15 7 9 8 2 1 4 9 14 17 8 17 15 3 4 15 15 2 2 3 16 13 2 9 12 ^ 33 0 14 6 6 5 2 13 4 16 11 3 10 18 2 15 5 9 4 8 4 18 18 17 18 3 14 12 9 11 15 16 1 9 16 ^ 32 1 18 5 10 6 7 17 7 12 3 13 8 12 3 8 9 3 17 12 8 18 6 14 3 6 14 14 10 14 13 17 18 8 ^ 36 1 18 12 17 9 17 2 12 5 9 12 1 18 10 5 5 2 18 3 6 16 18 3 1 2 10 15 2 5 8 16 10 14 3 9 8 13 ^ 33 1 16 14 1 16 15 16 17 4 12 12 16 5 3 9 14 5 7 17 12 11 12 18 14 2 7 7 15 8 3 5 1 8 13 ^ 34 1 7 6 7 14 9 15 15 18 16 3 10 5 16 6 8 11 4 1 10 1 16 4 12 17 15 14 8 5 4 6 4 17 16 16 ^ 38 0 4 5 18 18 12 9 3 9 6 9 7 6 10 15 4 9 17 5 17 5 6 1 6 2 8 17 7 7 4 4 13 16 3 4 10 16 12 13 ^ 33 0 16 7 18 3 3 11 9 13 14 15 18 2 12 10 3 15 3 1 10 6 15 13 17 13 5 9 7 11 9 5 18 15 12 ^ 33 1 16 11 1 6 18 13 8 1 18 8 1 5 13 1 18 5 15 15 16 12 13 2 17 12 14 17 8 1 10 12 10 4 18 ^ 34 0 5 6 18 18 7 10 13 14 10 12 7 4 10 8 16 16 15 5 13 14 4 14 2 4 12 6 11 5 17 8 5 1 14 16 ^ 31 1 17 9 11 2 11 11 3 13 13 11 12 13 5 12 12 11 6 13 4 18 15 12 18 6 6 7 15 13 12 14 16 ^ 38 1 4 11 2 5 6 12 10 2 7 15 11 8 14 7 16 16 1 4 3 9 14 16 3 18 1 7 17 1 7 3 16 17 6 16 12 5 3 17 ^ 40 1 10 15 18 10 8 10 2 5 11 2 7 3 5 6 7 1 12 2 9 2 4 15 1 11 11 17 3 3 16 8 3 11 18 16 11 6 15 8 8 13 ^ 40 1 10 3 17 7 10 18 13 14 8 7 8 14 2 2 8 6 3 7 5 6 9 5 12 10 7 6 5 16 4 14 2 15 3 15 9 15 1 9 7 12 ^ 35 0 14 15 12 7 2 16 18 8 18 1 13 12 1 1 14 14 13 3 14 7 2 10 10 11 14 3 12 5 13 6 17 14 1 11 13 ^ 34 0 7 12 8 12 17 17 18 17 13 2 4 7 5 1 15 7 14 17 11 6 10 9 18 9 14 13 3 8 4 13 8 7 13 7 ^ 35 0 4 16 8 17 10 2 13 10 2 2 6 2 3 18 17 2 17 4 18 7 16 18 14 4 11 7 4 15 17 6 11 11 14 17 4 ^ 37 0 10 17 16 13 15 14 6 1 14 11 8 16 6 2 16 13 7 8 6 2 15 1 9 12 4 4 11 13 7 2 11 9 18 4 5 4 18 ^ 39 0 2 14 9 9 1 8 13 11 15 8 5 9 10 16 9 2 7 1 1 17 13 6 11 10 8 5 12 15 6 15 10 12 4 18 1 2 8 11 15 ^ 32 1 16 10 12 18 11 16 12 11 17 17 4 7 13 7 10 7 10 6 1 12 7 18 11 18 2 10 15 10 14 8 18 2 ^ 40 1 9 12 12 3 13 12 6 4 9 17 13 13 5 7 3 2 1 17 14 4 16 6 13 1 13 6 6 10 1 3 18 3 11 7 9 5 7 11 17 12 ^ 36 1 9 16 5 15 10 17 3 8 15 17 8 15 11 3 15 17 11 1 1 4 3 14 18 4 2 18 8 15 6 4 6 3 15 11 16 8 ^ 39 1 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 3 2 12 2 14 12 4 1 5 11 16 18 16 8 11 15 2 18 7 5 14 5 15 10 ^ 47 1 3 3 5 4 3 11 4 4 5 10 3 12 17 1 4 17 10 10 9 1 3 4 2 1 12 5 14 11 10 4 6 14 9 1 5 8 2 9 15 12 13 7 16 2 13 17 3 ^ 34 1 9 18 15 9 13 16 18 10 4 11 13 9 6 1 17 6 8 6 5 11 5 14 16 9 13 11 10 9 15 4 14 7 14 9 ^ 37 1 1 15 5 5 18 13 13 8 13 16 5 17 5 10 1 8 8 12 6 13 18 9 6 17 3 16 2 8 9 8 7 2 14 14 8 10 13 ^ 42 0 9 11 10 7 11 4 6 9 10 11 12 2 14 1 13 1 7 1 15 7 9 8 2 1 4 9 14 17 8 17 15 3 4 15 15 2 2 3 16 13 2 17 ^ 36 0 16 14 6 6 5 2 13 4 16 11 3 10 18 2 15 5 9 4 8 4 18 18 17 18 3 14 12 9 11 15 16 1 9 2 18 6 ^ 33 1 10 6 7 17 7 12 3 13 8 12 3 8 9 3 17 12 8 18 6 14 3 6 14 14 10 14 13 17 18 14 18 12 13 ^ 39 1 9 17 2 12 5 9 12 1 18 10 5 5 2 18 3 6 16 18 3 1 2 10 15 2 5 8 16 10 14 3 9 8 10 16 14 1 16 15 14 ^ 30 1 17 19 5 7 14 4 11 3 6 18 13 7 18 18 19 19 13 9 10 19 14 12 4 15 15 18 2 10 7 15 ^ 34 1 2 13 8 19 15 1 11 14 7 7 17 6 16 4 16 17 2 18 12 5 14 19 17 1 8 12 6 6 6 19 13 10 16 5 ^ 36 1 14 13 6 16 14 15 4 13 15 4 4 11 4 10 3 17 4 19 6 17 14 3 2 16 1 14 16 5 17 8 1 1 19 13 12 12 ^ 34 0 17 11 13 5 19 11 18 19 1 3 12 11 8 4 11 13 17 3 8 9 4 5 12 15 12 6 7 16 16 12 1 13 17 15 ^ 40 0 18 9 3 16 2 16 4 19 6 6 18 3 13 1 5 3 2 6 15 11 6 4 14 15 15 9 13 8 1 9 15 2 7 5 11 5 12 7 16 15 ^ 37 0 18 4 3 1 4 11 15 7 6 9 1 14 7 1 17 17 16 14 13 14 12 14 9 12 11 18 7 14 3 1 6 1 15 8 15 19 9 ^ 32 0 3 9 9 7 7 10 12 13 7 11 12 16 9 9 9 17 13 13 2 17 10 4 18 17 19 16 11 11 13 18 13 12 ^ 35 0 8 15 18 10 6 10 18 17 9 2 14 1 17 18 6 14 12 5 5 15 17 10 3 8 8 1 10 5 1 18 18 9 16 10 14 ^ 38 1 6 16 1 6 3 5 8 16 8 7 5 18 11 15 17 6 11 10 4 8 14 16 6 7 8 12 12 18 1 10 4 7 1 19 7 19 15 12 ^ 34 0 1 14 6 11 18 5 4 12 6 14 2 19 2 5 13 10 10 2 16 10 18 16 19 2 15 10 7 18 16 17 15 15 9 13 ^ 38 1 10 16 4 15 7 5 19 1 15 16 11 19 9 18 2 4 6 12 9 8 7 13 14 11 4 12 13 5 9 6 5 6 16 11 9 3 15 6 ^ 40 0 16 1 13 6 8 18 11 11 2 1 2 2 14 9 13 1 15 6 5 16 19 14 19 7 18 5 2 2 3 13 13 12 13 11 2 12 2 12 18 5 ^ 35 0 7 8 13 6 9 8 17 10 11 1 9 14 4 19 19 3 15 13 9 18 12 17 1 16 8 9 15 1 12 4 4 19 18 13 11 ^ 36 1 14 18 8 14 9 3 4 18 16 9 19 12 3 17 5 10 16 5 8 4 4 10 14 13 4 9 11 19 8 8 5 1 13 16 14 13 ^ 41 1 10 15 3 4 8 2 12 9 16 3 16 3 6 17 3 10 19 7 6 1 5 11 18 9 4 6 2 15 11 17 17 17 4 10 13 3 7 10 3 9 14 ^ 42 0 7 9 3 3 8 19 10 8 2 19 12 19 13 6 19 3 4 17 6 9 1 7 2 9 7 18 6 15 2 2 4 3 10 11 11 6 12 10 18 4 12 10 ^ 35 1 4 5 11 12 15 19 12 10 6 15 14 19 18 11 8 11 17 16 7 7 11 2 10 6 19 5 14 7 1 7 3 19 4 17 15 ^ 36 1 5 10 2 18 1 17 8 12 17 2 9 8 8 3 14 10 15 2 14 8 3 1 16 18 12 18 11 16 7 17 5 19 2 19 12 19 ^ 37 0 16 14 2 9 16 2 6 6 7 9 10 9 11 9 14 11 15 5 16 9 2 17 2 8 15 8 4 3 14 14 16 16 13 11 10 16 14 ^ 40 0 11 7 14 14 14 6 10 10 1 6 13 19 5 6 4 7 12 12 10 5 10 15 15 8 5 13 17 13 5 6 14 1 9 2 6 5 17 9 11 13 ^ 38 0 18 8 6 13 15 3 3 15 5 13 18 3 2 5 5 14 7 13 4 17 7 2 17 3 18 15 7 15 16 18 5 12 8 6 3 17 12 13 ^ 38 1 19 15 9 7 17 16 15 3 11 11 5 2 13 19 16 2 4 16 7 8 1 2 9 17 12 3 5 18 19 11 17 9 1 4 1 18 10 10 ^ 41 1 13 1 7 13 5 7 4 1 8 13 16 3 5 7 6 8 8 14 8 13 7 19 8 16 18 4 2 8 7 12 4 14 5 1 3 19 17 11 14 15 19 ^ 39 0 10 9 12 19 11 10 3 18 14 17 18 17 7 12 14 8 11 7 2 10 17 15 5 3 12 3 12 1 2 1 1 12 14 10 2 8 17 18 2 ^ 45 1 4 9 4 16 5 18 1 1 10 10 11 3 10 12 1 3 11 1 11 5 3 3 16 15 10 17 14 15 6 13 12 2 3 14 3 9 19 4 4 8 10 14 5 11 9 ^ 35 0 2 7 15 14 8 2 11 19 19 4 5 10 8 9 5 15 9 17 19 5 7 14 4 11 3 6 18 13 7 18 18 19 19 13 13 ^ 35 1 10 19 14 12 4 15 15 18 2 10 7 9 2 13 8 19 15 1 11 14 7 7 17 6 16 4 16 17 2 18 12 5 14 19 9 ^ 38 1 1 8 12 6 6 6 19 13 10 16 13 14 13 6 16 14 15 4 13 15 4 4 11 4 10 3 17 4 19 6 17 14 3 2 16 1 14 19 ^ 38 0 5 17 8 1 1 19 13 12 12 17 11 13 5 19 11 18 19 1 3 12 11 8 4 11 13 17 3 8 9 4 5 12 15 12 6 7 16 11 ^ 43 0 12 1 13 17 4 18 9 3 16 2 16 4 19 6 6 18 3 13 1 5 3 2 6 15 11 6 4 14 15 15 9 13 8 1 9 15 2 7 5 11 5 12 16 ^ 39 1 16 6 18 4 3 1 4 11 15 7 6 9 1 14 7 1 17 17 16 14 13 14 12 14 9 12 11 18 7 14 3 1 6 1 15 8 15 19 12 ^ 35 0 3 9 9 7 7 10 12 13 7 11 12 16 9 9 9 17 13 13 2 17 10 4 18 17 19 16 11 11 13 18 13 8 8 15 6 ^ 40 0 10 6 10 18 17 9 2 14 1 17 18 6 14 12 5 5 15 17 10 3 8 8 1 10 5 1 18 18 9 16 10 19 6 16 1 6 3 5 8 16 ^ 40 0 8 7 5 18 11 15 17 6 11 10 4 8 14 16 6 7 8 12 12 18 1 10 4 7 1 19 7 19 15 2 1 14 6 11 18 5 4 12 6 19 ^ 35 0 2 19 2 5 13 10 10 2 16 10 18 16 19 2 15 10 7 18 16 17 15 15 9 15 10 16 4 15 7 5 19 1 15 16 6 ^ 43 1 19 9 18 2 4 6 12 9 8 7 13 14 11 4 12 13 5 9 6 5 6 16 11 9 3 15 12 16 1 13 6 8 18 11 11 2 1 2 2 14 9 13 11 ^ 39 1 15 6 5 16 19 14 19 7 18 5 2 2 3 13 13 12 13 11 2 12 2 12 18 7 8 13 6 9 8 17 10 11 1 9 14 4 19 19 3 ^ 34 1 15 13 9 18 12 17 1 16 8 9 15 1 12 4 4 19 18 13 15 14 18 8 14 9 3 4 18 16 9 19 12 3 17 15 ^ 45 1 10 16 5 8 4 4 10 14 13 4 9 11 19 8 8 5 1 13 16 14 1 10 15 3 4 8 2 12 9 16 3 16 3 6 17 3 10 19 7 6 1 5 11 18 2 ^ 43 1 15 4 13 14 3 4 1 3 1 5 11 4 9 7 20 8 15 4 16 7 19 11 1 11 2 13 13 11 12 13 15 12 1 5 13 3 8 15 12 8 16 16 6 ^ 44 0 5 13 12 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 6 7 10 17 12 20 6 7 5 16 1 4 2 17 9 ^ 38 0 15 8 20 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 8 16 11 16 15 18 18 18 ^ 35 1 20 2 17 17 10 8 13 20 4 18 6 18 9 4 1 1 18 5 2 17 15 16 19 15 1 10 17 16 4 16 14 14 11 15 10 ^ 38 0 5 9 15 10 9 17 18 14 15 12 6 1 16 8 18 8 13 12 10 14 14 13 9 2 14 17 9 1 20 10 4 2 12 9 4 13 16 5 ^ 36 0 14 10 11 16 17 12 18 12 7 17 8 7 3 1 3 17 4 9 5 17 14 17 11 5 20 19 8 19 14 13 2 18 3 3 18 13 ^ 41 1 13 8 14 6 18 7 10 1 13 10 11 11 16 1 2 8 7 1 7 14 8 17 6 8 4 3 11 17 3 5 7 16 11 11 14 7 13 20 20 7 20 ^ 40 1 13 15 14 16 14 8 9 16 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 3 4 3 7 1 14 19 17 ^ 37 1 18 13 11 5 18 4 19 10 6 19 11 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 3 8 10 1 18 1 6 20 14 ^ 36 0 8 9 6 12 11 7 7 3 17 13 6 20 17 9 20 16 10 12 17 8 11 8 11 10 5 10 14 18 8 19 9 12 12 2 20 12 ^ 38 0 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 14 3 6 16 13 10 13 5 16 10 2 8 2 17 19 4 17 7 19 6 9 15 7 ^ 41 1 20 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 8 18 15 5 3 5 12 15 16 10 17 7 19 16 2 1 16 6 3 19 10 ^ 46 0 5 18 9 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 8 17 4 14 4 15 3 2 2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 5 ^ 41 1 10 2 3 1 10 12 15 14 11 20 3 16 14 9 4 18 1 19 20 9 5 12 13 6 6 1 9 13 7 15 9 8 5 19 3 16 9 8 10 20 8 ^ 39 1 11 13 19 5 7 16 18 16 4 4 4 6 9 13 10 19 15 3 14 6 4 12 10 15 15 4 8 13 13 9 18 13 6 4 7 20 4 20 7 ^ 31 1 18 18 12 16 13 19 19 5 7 2 6 11 18 9 18 6 11 14 14 18 10 13 19 20 17 11 14 5 19 20 13 ^ 46 1 20 1 1 4 13 10 6 5 6 19 18 1 3 9 14 20 7 18 7 15 2 3 15 5 1 1 2 6 13 1 19 6 14 16 5 15 11 13 3 6 11 2 20 8 1 20 ^ 37 0 4 20 19 3 18 3 8 19 7 8 12 14 12 19 11 15 6 19 1 19 4 10 16 17 7 17 1 2 13 18 12 2 18 19 2 7 15 ^ 42 1 9 18 8 5 14 2 5 4 4 20 14 13 7 8 14 8 1 7 19 9 7 11 12 4 19 12 10 19 20 4 4 1 8 2 16 16 8 20 2 1 20 13 ^ 37 1 1 15 7 6 20 10 14 9 12 19 18 20 6 14 6 5 6 17 14 12 12 16 4 2 19 14 15 17 7 12 11 12 8 14 1 17 7 ^ 39 0 15 18 2 4 10 18 11 17 5 9 17 4 19 5 5 8 6 2 20 15 6 5 18 11 3 10 20 10 16 3 12 7 5 14 18 15 14 9 14 ^ 44 0 14 7 6 15 9 3 4 8 8 12 19 2 9 16 19 6 16 20 5 3 19 7 4 7 4 5 10 5 1 18 7 17 6 3 3 13 16 2 3 20 16 12 6 16 ^ 38 0 17 19 2 2 11 19 13 4 15 8 1 12 9 20 2 5 2 10 20 5 15 13 7 13 15 19 17 11 9 15 8 15 17 9 6 16 8 13 ^ 38 1 18 10 8 8 10 15 13 8 4 5 15 6 12 13 1 17 12 4 7 18 10 12 10 3 15 20 5 19 8 17 20 13 14 10 9 12 17 5 ^ 46 1 10 18 6 6 15 4 13 14 3 4 1 3 1 5 11 4 9 7 20 8 15 4 16 7 19 11 1 11 2 13 13 11 12 13 15 12 1 5 13 3 8 15 12 8 16 6 ^ 45 1 17 5 13 12 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 6 7 10 17 12 20 6 7 5 16 1 4 2 17 16 ^ 40 0 15 8 20 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 8 16 11 16 15 18 18 3 20 19 ^ 38 0 17 17 10 8 13 20 4 18 6 18 9 4 1 1 18 5 2 17 15 16 19 15 1 10 17 16 4 16 14 14 11 15 2 5 9 15 10 15 ^ 38 0 17 18 14 15 12 6 1 16 8 18 8 13 12 10 14 14 13 9 2 14 17 9 1 20 10 4 2 12 9 4 13 16 7 14 10 11 16 19 ^ 39 0 12 18 12 7 17 8 7 3 1 3 17 4 9 5 17 14 17 11 5 20 19 8 19 14 13 2 18 3 3 18 17 13 8 14 6 18 7 10 12 ^ 41 0 13 10 11 11 16 1 2 8 7 1 7 14 8 17 6 8 4 3 11 17 3 5 7 16 11 11 14 7 13 20 20 7 16 13 15 14 16 14 8 9 16 ^ 43 1 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 3 4 3 7 1 14 19 19 18 13 11 5 18 4 19 10 6 19 4 ^ 41 1 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 3 8 10 1 18 1 6 20 12 8 9 6 12 11 7 7 3 17 13 6 20 17 9 15 ^ 37 0 16 10 12 17 8 11 8 11 10 5 10 14 18 8 19 9 12 12 2 20 13 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 16 ^ 43 0 3 6 16 13 10 13 5 16 10 2 8 2 17 19 4 17 7 19 6 9 15 15 20 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 14 ^ 43 1 18 15 5 3 5 12 15 16 10 17 7 19 16 2 1 16 6 3 19 12 5 18 9 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 2 ^ 45 0 17 4 14 4 15 3 2 2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 19 10 2 3 1 10 12 15 14 11 20 3 16 14 9 4 18 1 19 20 9 5 18 ^ 42 0 13 6 6 1 9 13 7 15 9 8 5 19 3 16 9 8 10 20 14 11 13 19 5 7 16 18 16 4 4 4 6 9 13 10 19 15 3 14 6 4 12 18 ^ 36 1 15 15 4 8 13 13 9 18 13 6 4 7 20 4 20 18 18 12 16 13 19 19 5 7 2 6 11 18 9 18 6 11 14 14 18 15 ^ 43 1 13 19 20 17 11 14 5 19 20 11 20 1 1 4 13 10 6 5 6 19 18 1 3 9 14 20 7 18 7 15 2 3 15 5 1 1 2 6 13 1 19 6 19 ^ 40 1 16 5 15 11 13 3 6 11 2 20 8 1 5 4 20 19 3 18 3 8 19 7 8 12 14 12 19 11 15 6 19 1 19 4 10 16 17 7 17 16 ^ 39 1 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 2 12 14 3 10 6 2 6 2 17 16 2 5 21 5 17 19 7 8 11 15 ^ 33 0 12 17 14 18 15 16 16 16 12 20 13 2 5 5 2 10 20 16 12 10 2 17 21 20 15 14 14 18 21 13 9 17 10 ^ 40 1 2 12 16 17 3 9 19 5 7 10 5 11 17 18 14 14 12 2 20 15 8 17 3 20 11 12 18 7 12 7 9 8 3 18 14 3 5 17 9 14 ^ 43 0 8 21 11 8 8 16 21 12 5 8 7 20 10 14 7 1 9 5 4 5 2 21 12 1 1 9 20 14 11 9 19 16 3 1 14 10 2 8 20 18 7 8 18 ^ 40 1 2 19 6 11 18 11 15 6 5 16 14 9 7 21 3 15 21 16 8 7 3 6 14 17 17 5 10 20 10 15 10 1 15 18 6 10 9 7 16 6 ^ 39 0 11 15 12 2 9 1 1 6 6 13 8 20 6 18 8 5 8 1 1 17 20 20 19 17 13 14 17 12 5 3 18 20 20 11 18 15 13 16 7 ^ 48 1 7 10 1 19 10 7 17 7 16 3 8 4 4 15 17 13 9 11 2 2 11 7 13 4 17 7 1 5 13 19 16 5 14 16 2 11 18 5 11 6 4 7 3 17 2 1 18 12 ^ 41 1 21 18 3 5 16 6 11 2 8 8 7 14 13 21 6 14 12 6 12 19 14 3 16 3 2 7 11 14 8 16 10 19 12 19 4 5 6 13 19 12 13 ^ 44 1 7 5 12 4 13 21 2 5 17 15 15 1 13 5 21 6 4 12 14 15 5 18 12 1 19 2 14 1 8 8 11 6 20 10 3 21 8 20 2 4 1 16 11 21 ^ 42 1 5 3 8 16 15 8 12 14 20 16 18 7 2 18 2 18 19 7 4 19 3 1 20 7 15 1 4 5 12 10 19 6 11 4 4 9 20 20 8 2 20 18 ^ 42 1 19 2 8 4 15 7 2 2 6 18 20 16 1 18 17 13 3 14 2 1 2 10 14 19 12 9 15 20 1 7 15 17 7 12 18 1 15 14 8 21 21 5 ^ 43 1 7 20 10 11 10 1 9 21 7 5 1 12 15 2 9 17 4 13 5 4 11 21 14 13 3 20 21 1 3 12 18 11 4 14 20 5 3 14 13 15 9 21 3 ^ 40 1 19 8 1 5 9 5 9 16 17 9 6 12 6 16 7 4 3 1 21 16 19 15 18 17 17 17 21 13 20 9 6 6 9 1 13 17 21 1 9 14 ^ 36 0 11 12 13 18 19 19 15 12 20 2 16 12 9 21 17 16 8 2 14 6 4 1 6 16 15 19 19 21 9 13 18 3 16 8 13 11 ^ 47 0 21 15 4 21 4 2 3 8 15 19 8 6 16 2 15 3 12 3 11 3 17 12 21 6 3 4 13 1 12 4 10 2 6 7 6 9 12 21 10 10 11 2 13 19 2 14 17 ^ 44 1 11 8 10 19 1 11 11 9 3 13 15 4 3 18 9 14 5 15 18 5 6 17 11 19 2 4 12 8 18 12 17 3 4 8 5 19 16 16 6 1 13 1 18 18 ^ 39 1 10 18 15 11 5 1 17 4 17 19 11 18 21 9 2 10 10 5 5 20 18 13 5 15 3 6 3 10 10 16 13 13 14 16 20 19 11 16 8 ^ 42 1 6 8 15 13 11 13 15 18 11 20 17 20 4 16 10 14 1 4 16 4 17 8 3 7 7 18 16 20 2 9 9 4 20 7 16 4 11 4 10 6 20 4 ^ 41 0 17 6 19 17 2 15 6 5 7 4 8 11 16 9 10 15 20 12 15 8 6 17 5 9 3 3 4 19 20 12 5 19 21 5 21 11 14 19 1 17 6 ^ 39 0 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 6 21 7 11 20 12 9 11 6 16 18 18 10 11 20 6 12 11 5 7 21 3 ^ 43 1 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 13 9 7 10 17 10 6 8 3 17 18 3 21 19 6 17 15 4 9 15 9 15 14 4 18 ^ 45 1 14 8 10 13 4 11 10 7 6 21 1 14 5 11 7 7 2 13 13 3 9 13 8 14 9 3 7 18 4 9 9 5 15 13 17 10 15 16 20 8 19 9 10 9 13 ^ 40 1 19 14 21 2 18 13 10 4 18 16 4 21 15 10 18 19 3 12 12 14 4 13 11 1 11 1 10 2 12 4 21 10 21 18 9 2 16 7 20 7 ^ 41 0 7 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 2 12 14 3 10 6 2 6 2 17 16 2 5 21 5 17 19 7 8 11 10 21 ^ 35 0 17 14 18 15 16 16 16 12 20 13 2 5 5 2 10 20 16 12 10 2 17 21 20 15 14 14 18 21 13 9 17 21 2 12 10 ^ 40 0 17 3 9 19 5 7 10 5 11 17 18 14 14 12 2 20 15 8 17 3 20 11 12 18 7 12 7 9 8 3 18 14 3 5 17 9 18 8 21 20 ^ 46 1 8 8 16 21 12 5 8 7 20 10 14 7 1 9 5 4 5 2 21 12 1 1 9 20 14 11 9 19 16 3 1 14 10 2 8 20 18 7 8 15 2 19 6 11 18 10 ^ 44 1 15 6 5 16 14 9 7 21 3 15 21 16 8 7 3 6 14 17 17 5 10 20 10 15 10 1 15 18 6 10 9 7 16 14 11 15 12 2 9 1 1 6 6 19 ^ 38 1 8 20 6 18 8 5 8 1 1 17 20 20 19 17 13 14 17 12 5 3 18 20 20 11 18 15 13 16 13 7 10 1 19 10 7 17 7 15 ^ 50 0 3 8 4 4 15 17 13 9 11 2 2 11 7 13 4 17 7 1 5 13 19 16 5 14 16 2 11 18 5 11 6 4 7 3 17 2 1 18 13 21 18 3 5 16 6 11 2 8 8 18 ^ 42 1 14 13 21 6 14 12 6 12 19 14 3 16 3 2 7 11 14 8 16 10 19 12 19 4 5 6 13 19 12 13 7 5 12 4 13 21 2 5 17 15 15 12 ^ 45 1 13 5 21 6 4 12 14 15 5 18 12 1 19 2 14 1 8 8 11 6 20 10 3 21 8 20 2 4 1 16 11 1 5 3 8 16 15 8 12 14 20 16 18 7 18 ^ 46 0 18 2 18 19 7 4 19 3 1 20 7 15 1 4 5 12 10 19 6 11 4 4 9 20 20 8 2 20 3 19 2 8 4 15 7 2 2 6 18 20 16 1 18 17 13 14 ^ 43 1 14 2 1 2 10 14 19 12 9 15 20 1 7 15 17 7 12 18 1 15 14 8 21 21 19 7 20 10 11 10 1 9 21 7 5 1 12 15 2 9 17 4 19 ^ 45 1 5 4 11 21 14 13 3 20 21 1 3 12 18 11 4 14 20 5 3 14 13 15 9 21 11 19 8 1 5 9 5 9 16 17 9 6 12 6 16 7 4 3 1 21 15 ^ 35 0 19 15 18 17 17 17 21 13 20 9 6 6 9 1 13 17 21 1 9 16 11 12 13 18 19 19 15 12 20 2 16 12 9 21 12 ^ 44 1 16 8 2 14 6 4 1 6 16 15 19 19 21 9 13 18 3 16 8 13 21 15 4 21 4 2 3 8 15 19 8 6 16 2 15 3 12 3 11 3 17 12 21 9 ^ 48 0 3 4 13 1 12 4 10 2 6 7 6 9 12 21 10 10 11 2 13 19 2 14 17 11 8 10 19 1 11 11 9 3 13 15 4 3 18 9 14 5 15 18 5 6 17 11 19 15 ^ 44 0 4 12 8 18 12 17 3 4 8 5 19 16 16 6 1 13 1 18 1 10 18 15 11 5 1 17 4 17 19 11 18 21 9 2 10 10 5 5 20 18 13 5 15 18 ^ 39 1 6 3 10 10 16 13 13 14 16 20 19 11 16 21 6 8 15 13 11 13 15 18 11 20 17 20 4 16 10 14 1 4 16 4 17 8 3 7 21 ^ 46 1 18 16 20 2 9 9 4 20 7 16 4 11 4 10 6 20 14 17 6 19 17 2 15 6 5 7 4 8 11 16 9 10 15 20 12 15 8 6 17 5 9 3 3 4 19 3 ^ 40 0 12 5 19 21 5 21 11 14 19 1 17 8 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 6 21 7 11 20 12 9 11 6 16 11 ^ 44 0 18 10 11 20 6 12 11 5 7 21 19 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 13 9 7 10 17 10 6 8 3 17 18 3 21 19 8 ^ 47 0 4 12 22 5 11 20 16 15 4 17 22 1 8 16 11 6 13 18 3 14 8 13 2 19 16 1 19 1 5 3 16 9 8 20 7 5 1 11 15 2 3 17 3 12 7 4 19 ^ 42 0 18 16 13 7 1 19 5 12 18 12 6 15 19 4 4 9 13 13 8 17 13 18 12 2 8 4 7 17 17 14 11 13 1 16 11 2 21 3 22 17 16 11 ^ 39 0 18 22 12 20 17 13 1 7 10 7 20 11 1 7 8 14 14 12 15 13 15 18 15 11 18 1 17 14 15 20 16 20 8 2 17 10 4 21 2 ^ 44 1 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 9 22 19 12 8 16 5 17 5 9 1 2 9 6 12 6 1 7 4 3 15 1 14 16 ^ 42 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 12 12 8 20 13 2 9 20 9 14 10 1 16 2 22 6 4 16 18 ^ 51 0 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 3 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 14 13 ^ 40 1 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 15 8 15 3 5 6 2 19 12 17 4 20 8 11 20 ^ 45 0 2 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 10 18 5 5 13 3 21 5 3 6 18 18 10 1 21 15 ^ 45 1 7 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 15 11 9 13 17 15 9 9 15 4 13 15 9 4 19 9 ^ 46 0 18 6 13 22 10 6 12 2 17 15 6 5 7 4 8 11 1 9 10 8 5 20 16 6 10 5 17 3 3 19 12 13 20 5 12 14 5 14 11 22 12 16 10 8 9 16 ^ 39 0 15 12 3 2 16 22 14 22 7 6 5 13 22 14 13 4 6 14 7 11 13 20 9 19 6 9 11 11 18 19 13 6 20 19 20 7 22 12 12 ^ 41 0 6 14 18 19 7 17 12 10 3 18 15 5 21 16 8 20 3 21 9 15 18 10 15 10 6 8 18 2 11 3 14 4 6 10 19 9 8 17 8 22 20 ^ 36 1 7 22 16 18 21 4 11 10 15 6 22 16 22 5 19 15 7 7 2 21 21 3 17 21 16 22 9 3 7 11 4 17 17 20 21 21 ^ 37 1 18 9 5 8 12 17 18 17 16 12 22 14 17 11 21 10 4 3 1 4 14 10 11 4 3 20 20 22 19 21 19 16 19 16 10 17 17 ^ 40 1 19 14 18 14 3 9 17 1 7 13 6 7 15 20 12 13 16 21 20 10 8 22 7 12 21 6 16 4 13 11 2 12 15 22 3 18 6 17 6 22 ^ 42 0 10 9 2 5 22 5 10 4 7 8 19 10 20 10 22 11 8 1 9 1 20 13 21 17 5 5 17 10 13 9 20 18 17 2 14 13 22 22 3 14 21 10 ^ 46 0 2 14 2 20 1 10 18 9 12 5 7 18 20 19 10 11 22 7 12 2 13 8 8 2 3 13 19 20 3 7 20 7 9 8 3 11 22 3 5 10 9 11 16 14 19 16 ^ 46 1 15 8 1 14 20 5 8 7 13 10 22 7 16 9 5 4 5 2 14 20 1 1 15 17 13 22 19 17 4 1 3 1 22 10 15 15 2 16 13 11 7 16 17 12 6 20 ^ 40 1 3 19 8 6 5 9 15 22 17 7 14 18 14 9 16 7 18 14 22 2 2 5 18 13 18 8 18 16 8 11 15 6 18 9 7 9 22 19 20 15 ^ 44 0 9 16 16 6 6 21 8 13 6 11 8 5 16 16 1 10 13 13 4 10 21 22 15 10 20 5 3 3 13 15 13 11 11 15 21 1 21 7 10 1 12 18 7 20 ^ 51 0 7 1 18 8 4 19 2 21 17 19 2 2 19 7 21 19 2 7 15 15 16 5 21 12 1 5 22 1 17 19 11 5 11 6 4 7 3 10 2 1 3 6 14 11 18 5 1 6 11 17 8 ^ 39 1 8 15 22 21 14 6 22 20 6 20 12 22 18 1 3 2 7 19 22 8 9 18 4 20 12 4 5 6 21 12 20 21 7 5 20 4 21 14 14 ^ 45 0 15 5 2 16 15 21 5 14 15 6 4 12 22 5 11 20 16 15 4 17 22 1 8 16 11 6 13 18 3 14 8 13 2 19 16 1 19 1 5 3 16 9 8 20 14 ^ 48 1 5 1 11 15 2 3 17 3 12 7 4 12 18 16 13 7 1 19 5 12 18 12 6 15 19 4 4 9 13 13 8 17 13 18 12 2 8 4 7 17 17 14 11 13 1 16 11 22 ^ 38 0 21 3 22 17 16 17 18 22 12 20 17 13 1 7 10 7 20 11 1 7 8 14 14 12 15 13 15 18 15 11 18 1 17 14 15 20 16 10 ^ 43 0 8 2 17 10 4 21 5 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 9 22 19 12 8 16 5 17 5 9 1 2 9 6 12 22 ^ 47 1 1 7 4 3 15 1 14 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 12 12 8 20 13 2 9 20 9 14 10 1 16 2 22 20 ^ 53 0 4 16 14 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 3 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 15 ^ 42 1 10 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 15 8 15 3 5 6 2 19 12 17 4 20 8 11 20 12 ^ 45 0 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 10 18 5 5 13 3 21 5 3 6 18 18 10 1 21 21 18 ^ 45 0 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 15 11 9 13 17 15 9 9 15 4 13 15 9 4 19 19 19 ^ 49 0 6 13 22 10 6 12 2 17 15 6 5 7 4 8 11 1 9 10 8 5 20 16 6 10 5 17 3 3 19 12 13 20 5 12 14 5 14 11 22 12 16 10 8 9 4 15 12 3 22 ^ 39 0 16 22 14 22 7 6 5 13 22 14 13 4 6 14 7 11 13 20 9 19 6 9 11 11 18 19 13 6 20 19 20 7 22 12 11 6 14 18 17 ^ 43 1 7 17 12 10 3 18 15 5 21 16 8 20 3 21 9 15 18 10 15 10 6 8 18 2 11 3 14 4 6 10 19 9 8 17 8 22 4 7 22 16 18 21 11 ^ 39 0 11 10 15 6 22 16 22 5 19 15 7 7 2 21 21 3 17 21 16 22 9 3 7 11 4 17 17 20 21 10 18 9 5 8 12 17 18 17 17 ^ 40 1 12 22 14 17 11 21 10 4 3 1 4 14 10 11 4 3 20 20 22 19 21 19 16 19 16 10 17 20 19 14 18 14 3 9 17 1 7 13 6 18 ^ 44 1 15 20 12 13 16 21 20 10 8 22 7 12 21 6 16 4 13 11 2 12 15 22 3 18 6 17 6 2 10 9 2 5 22 5 10 4 7 8 19 10 20 10 22 7 ^ 43 0 8 1 9 1 20 13 21 17 5 5 17 10 13 9 20 18 17 2 14 13 22 22 3 14 21 9 2 14 2 20 1 10 18 9 12 5 7 18 20 19 10 11 19 ^ 53 1 7 12 2 13 8 8 2 3 13 19 20 3 7 20 7 9 8 3 11 22 3 5 10 9 11 16 14 19 8 15 8 1 14 20 5 8 7 13 10 22 7 16 9 5 4 5 2 14 20 1 1 15 8 ^ 42 0 13 22 19 17 4 1 3 1 22 10 15 15 2 16 13 11 7 16 17 12 6 19 3 19 8 6 5 9 15 22 17 7 14 18 14 9 16 7 18 14 22 19 ^ 43 0 2 5 18 13 18 8 18 16 8 11 15 6 18 9 7 9 22 19 20 17 9 16 16 6 6 21 8 13 6 11 8 5 16 16 1 10 13 13 4 10 21 22 14 ^ 48 0 10 20 5 3 3 13 15 13 11 11 15 21 1 21 7 10 1 12 18 7 2 7 1 18 8 4 19 2 21 17 19 2 2 19 7 21 19 2 7 15 15 16 5 21 12 1 5 21 ^ 49 1 1 17 19 11 5 11 6 4 7 3 10 2 1 3 6 14 11 18 5 1 6 11 17 8 8 15 22 21 14 6 22 20 6 20 12 22 18 1 3 2 7 19 22 8 9 18 4 20 10 ^ 45 1 4 5 6 21 12 20 21 7 5 20 4 21 14 2 15 5 2 16 15 21 5 14 15 6 4 12 22 5 11 20 16 15 4 17 22 1 8 16 11 6 13 18 3 14 13 ^ 52 0 13 2 19 16 1 19 1 5 3 16 9 8 20 7 5 1 11 15 2 3 17 3 12 7 4 12 18 16 13 7 1 19 5 12 18 12 6 15 19 4 4 9 13 13 8 17 13 18 12 2 8 15 ^ 46 0 20 1 1 11 21 2 3 16 8 12 21 22 1 16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 16 7 9 18 11 11 17 20 2 7 10 20 8 10 16 14 14 ^ 41 1 20 4 16 4 18 1 14 12 19 13 15 19 19 11 22 13 10 2 11 16 10 17 8 8 6 22 2 15 10 9 13 18 14 22 8 6 18 16 15 14 20 ^ 43 1 14 3 12 14 17 11 3 9 19 10 20 16 11 3 17 7 21 23 12 23 11 13 2 14 14 16 13 12 11 5 14 3 8 4 13 8 17 17 18 17 2 12 22 ^ 43 1 17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 13 21 21 3 18 13 20 11 18 19 11 6 1 10 18 7 17 5 16 1 7 10 4 20 22 ^ 46 0 8 10 12 4 11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 13 6 20 1 9 12 8 5 23 17 16 8 8 3 10 13 7 6 10 8 14 9 15 20 20 ^ 46 0 20 21 15 12 19 17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 21 18 19 15 16 12 6 12 17 8 7 8 11 14 1 23 10 15 15 13 ^ 43 0 21 13 15 18 21 10 10 23 3 13 13 9 16 2 17 19 3 22 11 5 18 19 13 7 7 8 19 2 12 2 19 16 23 9 16 6 3 19 12 5 10 9 17 ^ 47 0 21 3 2 1 7 14 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 11 ^ 44 0 4 15 17 11 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 15 ^ 37 0 8 4 20 22 6 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 23 18 10 12 8 21 11 19 ^ 39 0 12 7 19 14 18 14 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 22 14 21 9 21 3 ^ 45 1 14 14 4 18 13 12 23 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 22 19 13 8 5 19 7 5 23 3 ^ 50 1 4 19 11 23 11 21 14 1 3 20 2 20 7 4 17 2 5 13 4 23 5 22 7 7 9 17 13 5 6 2 21 1 17 7 9 21 23 1 1 12 3 1 15 22 4 12 6 20 5 23 ^ 46 1 23 4 12 22 8 18 16 3 16 4 2 13 1 15 15 1 23 2 3 4 10 1 12 7 11 2 7 22 22 21 22 13 3 12 22 12 4 3 23 10 14 17 15 9 23 20 ^ 44 0 19 12 21 22 9 17 12 2 18 18 12 21 2 19 4 21 20 4 9 14 5 21 8 22 10 15 23 14 8 5 11 19 5 7 5 3 11 4 15 18 9 2 23 4 ^ 46 0 9 16 14 15 6 15 1 11 4 16 16 20 14 2 9 19 14 6 3 7 10 16 22 23 7 7 12 5 2 8 9 5 7 1 17 19 21 19 18 15 3 20 22 14 9 16 ^ 44 1 10 18 11 3 5 9 10 11 22 12 12 15 23 2 10 18 23 5 18 21 20 23 3 9 3 22 7 8 7 4 1 14 16 16 13 18 2 21 18 15 5 5 16 21 ^ 46 0 2 2 6 23 13 22 20 12 17 4 10 21 2 20 2 8 8 7 20 13 3 20 23 16 6 23 9 12 20 3 10 5 6 19 18 12 13 14 8 1 1 8 9 13 19 23 ^ 47 0 9 20 20 5 15 13 17 3 15 22 3 1 19 8 15 8 19 9 21 7 12 1 16 21 11 8 10 15 16 8 1 5 5 20 22 13 11 22 4 4 7 6 22 10 3 21 4 ^ 45 1 9 19 22 18 3 23 6 4 6 19 15 13 17 4 13 9 15 4 6 7 13 11 1 20 15 12 18 18 16 7 13 4 11 7 11 6 17 9 18 15 21 17 5 20 11 ^ 49 0 1 22 16 18 5 8 11 2 23 10 11 5 2 1 19 16 3 19 16 15 21 5 3 7 18 4 9 15 3 8 20 1 21 1 21 17 9 6 17 10 16 2 9 7 16 19 15 17 9 ^ 51 0 17 20 19 6 6 14 2 2 5 1 2 10 17 1 18 6 18 20 1 1 11 21 2 3 16 8 12 21 22 1 16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 16 7 9 18 17 ^ 45 1 11 17 20 2 7 10 20 8 10 16 14 11 20 4 16 4 18 1 14 12 19 13 15 19 19 11 22 13 10 2 11 16 10 17 8 8 6 22 2 15 10 9 13 18 8 ^ 44 0 22 8 6 18 16 15 14 15 14 3 12 14 17 11 3 9 19 10 20 16 11 3 17 7 21 23 12 23 11 13 2 14 14 16 13 12 11 5 14 3 8 4 13 20 ^ 43 0 17 17 18 17 2 12 3 17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 13 21 21 3 18 13 20 11 18 19 11 6 1 10 18 7 17 20 ^ 50 1 16 1 7 10 4 20 10 8 10 12 4 11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 13 6 20 1 9 12 8 5 23 17 16 8 8 3 10 13 7 6 10 8 14 17 ^ 46 1 15 20 18 20 21 15 12 19 17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 21 18 19 15 16 12 6 12 17 8 7 8 11 14 1 23 21 ^ 45 0 15 15 2 21 13 15 18 21 10 10 23 3 13 13 9 16 2 17 19 3 22 11 5 18 19 13 7 7 8 19 2 12 2 19 16 23 9 16 6 3 19 12 5 10 15 ^ 48 1 20 21 3 2 1 7 14 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 12 ^ 47 0 4 15 17 11 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 4 8 4 20 ^ 39 0 22 6 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 23 18 10 12 8 21 11 6 12 7 19 14 14 ^ 40 0 14 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 22 14 21 9 21 19 14 14 4 18 13 12 ^ 46 0 23 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 22 19 13 8 5 19 7 5 23 1 4 19 11 23 11 21 9 ^ 52 0 1 3 20 2 20 7 4 17 2 5 13 4 23 5 22 7 7 9 17 13 5 6 2 21 1 17 7 9 21 23 1 1 12 3 1 15 22 4 12 6 20 5 19 23 4 12 22 8 18 16 3 22 ^ 48 0 4 2 13 1 15 15 1 23 2 3 4 10 1 12 7 11 2 7 22 22 21 22 13 3 12 22 12 4 3 23 10 14 17 15 9 23 4 19 12 21 22 9 17 12 2 18 18 9 ^ 46 0 21 2 19 4 21 20 4 9 14 5 21 8 22 10 15 23 14 8 5 11 19 5 7 5 3 11 4 15 18 9 2 23 22 9 16 14 15 6 15 1 11 4 16 16 20 22 ^ 47 0 2 9 19 14 6 3 7 10 16 22 23 7 7 12 5 2 8 9 5 7 1 17 19 21 19 18 15 3 20 22 14 9 11 10 18 11 3 5 9 10 11 22 12 12 15 23 22 ^ 45 0 10 18 23 5 18 21 20 23 3 9 3 22 7 8 7 4 1 14 16 16 13 18 2 21 18 15 5 5 16 12 2 2 6 23 13 22 20 12 17 4 10 21 2 20 19 ^ 47 0 8 8 7 20 13 3 20 23 16 6 23 9 12 20 3 10 5 6 19 18 12 13 14 8 1 1 8 9 13 19 12 9 20 20 5 15 13 17 3 15 22 3 1 19 8 15 23 ^ 48 0 19 9 21 7 12 1 16 21 11 8 10 15 16 8 1 5 5 20 22 13 11 22 4 4 7 6 22 10 3 21 1 9 19 22 18 3 23 6 4 6 19 15 13 17 4 13 9 17 ^ 49 1 4 6 7 13 11 1 20 15 12 18 18 16 7 13 4 11 7 11 6 17 9 18 15 21 17 5 20 6 1 22 16 18 5 8 11 2 23 10 11 5 2 1 19 16 3 19 16 15 18 ^ 55 1 5 3 7 18 4 9 15 3 8 20 1 21 1 21 17 9 6 17 10 16 2 9 7 16 19 15 17 10 17 20 19 6 6 14 2 2 5 1 2 10 17 1 18 6 18 20 1 1 11 21 2 3 16 8 17 ^ 47 0 21 22 1 16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 16 7 9 18 11 11 17 20 2 7 10 20 8 10 16 14 11 20 4 16 4 18 1 14 12 19 13 19 ^ 45 1 19 19 11 22 13 10 2 11 16 10 17 8 8 6 22 2 15 10 9 13 18 14 22 8 6 18 16 15 14 15 14 3 12 14 17 11 3 9 19 10 20 16 11 3 21 ^ 47 1 7 21 23 12 23 11 13 2 14 14 16 13 12 11 5 14 3 8 4 13 8 17 17 18 17 2 12 3 17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 20 ^ 47 1 21 21 3 18 13 20 11 18 19 11 6 1 10 18 7 17 5 16 1 7 10 4 20 10 8 10 12 4 11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 13 22 ^ 51 0 20 1 9 12 8 5 23 17 16 8 8 3 10 13 7 6 10 8 14 9 15 20 18 20 21 15 12 19 17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 21 21 ^ 52 0 15 13 4 8 12 22 9 6 3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 2 5 21 2 7 22 4 5 23 3 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 21 ^ 51 1 10 21 4 8 24 2 6 19 10 6 22 22 14 22 13 21 5 22 2 4 18 5 11 21 1 7 8 4 17 5 14 1 2 10 9 12 5 11 10 20 4 14 3 1 3 21 12 11 17 22 21 ^ 43 1 7 5 21 14 15 19 20 12 6 12 18 19 4 7 12 10 5 22 3 15 21 7 23 7 2 22 4 18 18 3 24 10 17 24 23 18 6 11 18 22 8 6 20 ^ 45 0 2 12 10 14 12 9 2 23 16 20 14 17 9 16 7 21 6 22 24 19 11 9 19 21 15 11 19 2 2 7 8 10 8 9 8 15 9 14 6 16 8 21 21 22 13 ^ 50 1 17 9 4 24 21 15 15 16 16 13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 13 22 3 5 1 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 5 3 22 ^ 47 0 8 12 20 20 9 2 13 24 17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 24 20 14 7 17 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 22 ^ 48 1 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 7 16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 19 ^ 45 1 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 18 17 18 7 11 12 21 6 12 4 7 18 17 18 ^ 44 0 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 19 14 10 18 15 14 12 ^ 50 1 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 9 2 24 5 20 13 7 20 17 19 11 ^ 43 0 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 4 24 7 21 18 2 21 16 1 19 18 20 11 3 15 19 18 1 6 14 15 ^ 45 0 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 1 10 2 18 1 21 19 5 18 12 2 22 16 23 15 19 6 18 9 1 23 20 ^ 49 0 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 21 4 19 5 5 24 ^ 46 0 24 13 23 6 24 5 17 12 5 1 15 17 17 21 11 13 9 23 11 14 21 7 6 9 6 14 7 16 2 17 1 24 23 4 12 14 4 2 11 23 12 4 23 21 21 4 ^ 49 1 15 13 15 14 15 8 14 9 17 7 15 2 23 2 1 17 6 14 19 24 2 8 8 7 7 10 14 13 7 9 11 16 11 8 8 18 13 13 18 10 1 20 18 22 19 12 9 16 12 ^ 43 1 13 6 9 17 20 10 5 7 20 18 8 15 23 21 20 5 15 11 3 3 14 21 10 24 6 21 21 6 23 10 3 21 23 17 20 8 16 10 22 5 16 1 24 ^ 50 0 24 3 9 16 6 7 3 20 12 17 18 21 5 9 7 1 9 12 19 5 7 6 24 11 11 20 23 10 4 7 1 19 7 19 17 23 15 5 12 21 20 3 1 14 2 15 22 3 16 11 ^ 45 1 10 19 10 20 16 19 17 10 4 21 20 16 21 14 14 8 17 10 19 1 17 4 3 22 23 14 16 9 22 8 20 24 1 5 11 11 6 4 13 15 12 1 11 13 22 ^ 45 0 3 8 5 6 5 16 12 11 2 17 14 19 23 16 5 6 20 21 9 24 9 22 23 22 12 8 13 23 17 5 3 16 22 15 22 7 17 3 2 13 13 11 24 13 17 ^ 42 1 21 11 14 20 24 24 4 9 13 5 8 9 18 7 12 1 21 8 24 15 1 22 19 24 14 13 8 20 14 18 23 19 9 8 14 23 11 4 4 22 20 17 ^ 49 1 17 15 20 6 15 8 24 4 20 19 8 19 14 21 24 18 3 10 16 3 6 4 1 10 15 13 4 8 12 22 9 6 3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 23 ^ 50 0 5 21 2 7 22 4 5 23 3 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 8 10 21 4 8 24 2 6 19 10 6 22 22 14 22 13 21 5 22 2 4 18 5 24 ^ 53 1 21 1 7 8 4 17 5 14 1 2 10 9 12 5 11 10 20 4 14 3 1 3 21 12 11 17 22 11 7 5 21 14 15 19 20 12 6 12 18 19 4 7 12 10 5 22 3 15 21 7 23 7 18 ^ 43 1 22 4 18 18 3 24 10 17 24 23 18 6 11 18 22 8 6 6 2 12 10 14 12 9 2 23 16 20 14 17 9 16 7 21 6 22 24 19 11 9 19 21 6 ^ 49 1 11 19 2 2 7 8 10 8 9 8 15 9 14 6 16 8 21 21 22 6 17 9 4 24 21 15 15 16 16 13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 13 22 3 5 22 ^ 52 0 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 5 3 18 8 12 20 20 9 2 13 24 17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 24 20 14 7 23 ^ 45 1 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 16 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 23 ^ 51 1 16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 15 ^ 48 1 17 18 7 11 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 20 ^ 49 1 24 24 19 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 24 ^ 43 0 2 24 5 20 13 7 20 17 19 22 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 4 24 7 21 18 2 21 16 1 19 11 ^ 48 1 20 11 3 15 19 18 1 6 14 5 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 1 10 2 18 1 21 19 5 18 12 2 22 16 23 19 ^ 50 1 19 6 18 9 1 23 22 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 ^ 48 1 16 21 4 19 5 5 20 24 13 23 6 24 5 17 12 5 1 15 17 17 21 11 13 9 23 11 14 21 7 6 9 6 14 7 16 2 17 1 24 23 4 12 14 4 2 11 23 15 ^ 50 1 4 23 21 21 16 15 13 15 14 15 8 14 9 17 7 15 2 23 2 1 17 6 14 19 24 2 8 8 7 7 10 14 13 7 9 11 16 11 8 8 18 13 13 18 10 1 20 18 22 3 ^ 44 1 12 9 16 17 13 6 9 17 20 10 5 7 20 18 8 15 23 21 20 5 15 11 3 3 14 21 10 24 6 21 21 6 23 10 3 21 23 17 20 8 16 10 22 12 ^ 53 0 16 1 5 24 3 9 16 6 7 3 20 12 17 18 21 5 9 7 1 9 12 19 5 7 6 24 11 11 20 23 10 4 7 1 19 7 19 17 23 15 5 12 21 20 3 1 14 2 15 22 3 16 9 ^ 46 1 10 19 10 20 16 19 17 10 4 21 20 16 21 14 14 8 17 10 19 1 17 4 3 22 23 14 16 9 22 8 20 24 1 5 11 11 6 4 13 15 12 1 11 13 21 21 ^ 46 0 8 5 6 5 16 12 11 2 17 14 19 23 16 5 6 20 21 9 24 9 22 23 22 12 8 13 23 17 5 3 16 22 15 22 7 17 3 2 13 13 11 24 13 12 21 7 ^ 43 1 14 20 24 24 4 9 13 5 8 9 18 7 12 1 21 8 24 15 1 22 19 24 14 13 8 20 14 18 23 19 9 8 14 23 11 4 4 22 20 13 17 15 24 ^ 55 0 6 15 8 24 4 20 19 8 19 14 21 24 18 3 10 16 3 6 4 1 10 15 13 4 8 12 22 9 6 3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 2 5 21 2 7 22 4 5 23 4 ^ 55 1 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 8 10 21 4 8 24 2 6 19 10 6 22 22 14 22 13 21 5 22 2 4 18 5 11 21 1 7 8 4 17 5 14 1 2 10 9 12 14 ^ 49 0 11 10 20 4 14 3 1 3 21 12 11 17 22 11 7 5 21 14 15 19 20 12 6 12 18 19 4 7 12 10 5 22 3 15 21 7 23 7 2 22 4 18 18 3 24 10 17 24 12 ^ 50 0 18 6 11 18 22 8 6 6 2 12 10 14 12 9 2 23 16 20 14 17 9 16 7 21 6 22 24 19 11 9 19 21 15 11 19 2 2 7 8 10 8 9 8 15 9 14 6 16 8 22 ^ 51 1 21 22 6 17 9 4 24 21 15 15 16 16 13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 13 22 3 5 1 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 21 ^ 51 1 5 3 18 8 12 20 20 9 2 13 24 17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 24 20 14 7 17 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 16 20 ^ 52 0 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 7 16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 16 ^ 49 1 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 18 17 18 7 11 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 16 ^ 47 0 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 19 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 3 ^ 45 0 17 6 24 11 7 21 9 17 8 25 5 5 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 24 18 12 21 19 2 4 24 13 11 2 7 24 22 17 21 ^ 46 1 15 1 8 3 10 15 18 15 8 10 16 20 20 7 18 22 11 18 9 11 15 22 20 18 6 24 15 25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 19 24 18 15 ^ 52 1 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 5 6 21 5 21 24 3 6 10 17 19 9 15 11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 21 20 7 22 18 ^ 43 0 9 24 4 18 7 7 25 24 22 21 23 24 14 20 12 6 7 4 2 12 25 15 3 9 23 8 16 25 11 14 4 10 19 23 16 13 9 20 25 17 11 8 19 ^ 55 0 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 17 25 3 ^ 46 0 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 ^ 50 1 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 11 ^ 44 1 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 19 ^ 51 0 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 11 20 ^ 47 0 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 25 ^ 55 1 4 8 18 3 18 3 11 24 2 14 9 1 10 4 4 13 19 22 4 7 19 5 10 10 1 8 22 22 6 8 13 12 11 17 23 14 16 7 5 11 22 24 7 2 11 13 18 4 20 8 1 6 25 20 16 ^ 51 1 20 1 25 10 15 15 2 17 13 9 24 17 24 20 13 15 17 3 11 20 10 5 13 23 18 5 3 18 15 7 5 7 4 15 20 16 2 17 1 7 4 12 7 25 14 1 4 7 19 19 22 ^ 52 0 3 13 12 4 3 14 4 14 11 6 3 25 18 16 20 24 12 19 18 25 6 23 6 15 5 4 4 6 14 13 20 5 14 15 2 13 21 11 5 17 2 2 10 11 13 14 12 11 21 15 23 20 ^ 50 1 2 5 7 23 10 20 6 12 1 19 10 24 21 22 25 16 12 19 22 15 10 18 24 1 5 16 10 18 2 19 14 3 5 1 7 20 7 16 6 20 6 6 25 10 22 20 2 1 15 18 ^ 48 0 23 25 23 4 11 15 15 6 9 22 22 19 22 25 6 19 6 2 20 21 7 22 18 10 7 17 4 16 12 10 25 12 23 23 9 2 22 1 20 2 8 3 14 7 1 2 3 24 ^ 38 1 21 21 23 20 22 11 25 20 24 25 1 9 21 20 14 10 14 19 9 17 15 13 5 15 24 21 12 13 25 22 21 1 16 23 7 24 15 22 ^ 54 1 22 5 25 3 4 2 9 12 24 6 19 1 14 9 5 9 1 17 9 4 23 21 1 3 15 16 11 1 12 18 6 2 7 8 17 8 21 13 22 9 21 4 9 1 13 17 21 10 9 18 24 23 13 24 ^ 43 1 23 23 19 23 22 17 18 23 18 21 17 1 10 12 4 6 1 21 11 18 2 6 6 12 18 13 16 16 18 19 13 11 21 19 15 12 15 16 19 2 23 19 23 ^ 48 0 1 2 25 14 11 25 24 16 8 14 21 21 16 6 13 1 23 15 8 17 4 3 4 9 23 12 8 8 24 13 6 11 3 8 24 19 8 23 1 24 24 18 25 13 2 6 25 14 ^ 51 1 9 3 5 11 19 11 16 5 4 17 24 23 15 14 10 7 14 17 25 15 10 14 6 18 18 4 1 13 10 16 1 25 16 2 24 5 1 17 6 17 6 24 11 7 21 9 17 8 25 5 23 ^ 48 1 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 24 18 12 21 19 2 4 24 13 11 2 7 24 22 17 5 15 1 8 3 10 15 18 15 8 10 16 20 20 7 25 ^ 49 0 22 11 18 9 11 15 22 20 18 6 24 15 25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 19 24 18 9 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 17 ^ 47 1 6 21 5 21 24 3 6 10 17 19 9 15 11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 21 20 7 22 14 9 24 4 18 7 7 25 24 22 21 23 24 14 ^ 53 0 20 12 6 7 4 2 12 25 15 3 9 23 8 16 25 11 14 4 10 19 23 16 13 9 20 25 17 11 8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 ^ 54 1 7 8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 25 ^ 44 1 6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 25 ^ 49 1 7 23 11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 25 ^ 45 1 12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 22 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 7 ^ 58 0 11 19 1 21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 7 ^ 54 1 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 11 4 8 18 3 18 3 11 24 2 14 9 1 10 4 4 13 19 22 4 7 19 5 10 10 1 8 22 22 6 8 13 12 11 21 ^ 47 1 23 14 16 7 5 11 22 24 7 2 11 13 18 4 20 8 1 6 25 20 17 20 1 25 10 15 15 2 17 13 9 24 17 24 20 13 15 17 3 11 20 10 5 13 23 18 21 ^ 57 1 3 18 15 7 5 7 4 15 20 16 2 17 1 7 4 12 7 25 14 1 4 7 19 19 20 3 13 12 4 3 14 4 14 11 6 3 25 18 16 20 24 12 19 18 25 6 23 6 15 5 4 4 6 14 13 20 7 ^ 51 1 14 15 2 13 21 11 5 17 2 2 10 11 13 14 12 11 21 15 23 3 2 5 7 23 10 20 6 12 1 19 10 24 21 22 25 16 12 19 22 15 10 18 24 1 5 16 10 18 2 19 8 ^ 49 0 3 5 1 7 20 7 16 6 20 6 6 25 10 22 20 2 1 15 14 23 25 23 4 11 15 15 6 9 22 22 19 22 25 6 19 6 2 20 21 7 22 18 10 7 17 4 16 12 24 ^ 46 0 10 25 12 23 23 9 2 22 1 20 2 8 3 14 7 1 2 3 19 21 21 23 20 22 11 25 20 24 25 1 9 21 20 14 10 14 19 9 17 15 13 5 15 24 21 14 ^ 55 0 13 25 22 21 1 16 23 7 24 15 3 22 5 25 3 4 2 9 12 24 6 19 1 14 9 5 9 1 17 9 4 23 21 1 3 15 16 11 1 12 18 6 2 7 8 17 8 21 13 22 9 21 4 9 22 ^ 45 1 13 17 21 10 9 18 24 23 13 7 23 23 19 23 22 17 18 23 18 21 17 1 10 12 4 6 1 21 11 18 2 6 6 12 18 13 16 16 18 19 13 11 21 19 8 ^ 50 1 12 15 16 19 2 23 19 4 1 2 25 14 11 25 24 16 8 14 21 21 16 6 13 1 23 15 8 17 4 3 4 9 23 12 8 8 24 13 6 11 3 8 24 19 8 23 1 24 24 12 ^ 53 0 25 13 2 6 25 7 9 3 5 11 19 11 16 5 4 17 24 23 15 14 10 7 14 17 25 15 10 14 6 18 18 4 1 13 10 16 1 25 16 2 24 5 1 17 6 17 6 24 11 7 21 9 19 ^ 51 1 8 25 5 5 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 24 18 12 21 19 2 4 24 13 11 2 7 24 22 17 5 15 1 8 3 10 15 18 15 8 10 16 20 20 8 ^ 50 1 18 22 11 18 9 11 15 22 20 18 6 24 15 25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 19 24 18 9 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 18 ^ 48 1 6 21 5 21 24 3 6 10 17 19 9 15 11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 21 20 7 22 14 9 24 4 18 7 7 25 24 22 21 23 24 14 19 ^ 55 0 12 6 7 4 2 12 25 15 3 9 23 8 16 25 11 14 4 10 19 23 16 13 9 20 25 17 11 8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 24 ^ 56 0 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 22 ^ 47 0 15 13 24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 12 ^ 49 0 4 8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 22 ^ 46 1 23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 22 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 20 ^ 57 1 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 21 18 10 20 25 7 ^ 56 1 3 17 17 5 8 22 25 19 8 10 19 7 11 4 8 18 3 18 3 11 24 2 14 9 1 10 4 4 13 19 22 4 7 19 5 10 10 1 8 22 22 6 8 13 12 11 17 23 14 16 7 5 11 22 24 18 ^ 54 1 2 11 13 18 4 20 8 1 6 25 20 17 20 1 25 10 15 15 2 17 13 9 24 17 24 20 13 15 17 3 11 20 10 5 13 23 18 5 3 18 15 7 5 7 4 15 20 16 2 17 1 7 4 23 ^ 56 0 7 25 14 1 4 7 19 19 20 3 13 12 4 3 14 4 14 11 6 3 25 18 16 20 24 12 19 18 25 6 23 6 15 5 4 4 6 14 13 20 5 14 15 2 13 21 11 5 17 2 2 10 11 13 14 24 ^ 49 0 12 11 20 3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 19 ^ 54 0 18 6 12 19 25 7 6 5 2 14 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 7 ^ 56 0 20 25 6 19 8 3 22 16 16 16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 23 ^ 51 1 22 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 18 ^ 51 1 16 24 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 25 2 25 22 9 15 16 26 5 12 1 7 4 24 7 14 20 1 4 7 3 10 10 15 6 13 6 22 6 20 22 2 26 26 ^ 47 1 6 14 1 16 3 24 25 24 17 12 14 18 18 9 9 11 22 13 9 2 22 15 20 20 18 8 13 13 21 8 11 5 26 8 19 17 4 2 15 26 13 24 26 11 16 9 24 ^ 52 0 8 18 21 6 1 8 1 16 4 20 23 23 24 10 11 12 10 10 25 1 11 25 10 3 26 26 20 15 11 19 16 17 3 16 12 25 15 9 23 1 2 24 8 10 18 2 9 5 4 17 16 12 ^ 50 0 12 20 20 1 3 11 5 9 3 17 9 17 24 21 3 4 16 2 10 1 25 5 22 16 6 21 19 21 23 15 9 9 21 17 11 1 15 17 23 24 11 7 10 26 15 8 22 22 18 16 ^ 48 0 11 17 5 26 7 23 19 3 24 17 2 19 18 26 21 12 5 18 22 20 7 15 6 4 5 20 13 10 23 18 16 25 18 15 2 20 14 24 22 17 3 15 16 1 10 2 12 16 ^ 47 0 21 1 21 21 4 18 13 1 24 18 23 17 19 6 19 9 26 25 23 23 14 13 13 20 12 13 4 21 10 22 21 22 1 12 12 7 13 16 18 8 9 4 3 10 18 12 25 ^ 47 1 5 19 19 12 24 13 18 1 22 8 1 17 18 24 3 22 7 7 19 26 13 26 6 26 6 18 12 5 26 17 18 19 22 10 12 8 23 11 17 23 25 5 5 11 4 13 20 ^ 52 0 18 4 19 23 3 13 15 4 3 9 24 14 5 25 21 22 18 17 12 15 14 16 10 14 9 19 7 16 3 23 4 26 18 5 16 21 24 2 8 8 8 7 11 13 14 7 9 12 18 11 10 20 ^ 47 1 20 12 14 19 11 21 21 22 19 13 10 16 19 14 7 8 16 20 10 3 9 23 18 7 26 16 22 21 21 5 14 11 2 2 16 22 11 26 7 22 23 5 23 10 4 22 5 ^ 50 0 19 20 9 16 10 24 4 19 26 4 25 4 8 17 7 7 2 23 11 18 19 23 6 10 9 1 9 14 19 5 6 6 25 12 11 21 26 12 3 8 20 8 21 18 25 25 14 4 11 25 ^ 45 1 23 4 14 3 17 26 22 26 2 15 9 8 25 19 12 23 17 20 17 10 4 23 20 17 21 14 14 9 18 11 18 2 18 4 2 22 25 15 18 10 23 8 21 26 15 ^ 54 0 7 14 10 6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 25 16 5 7 20 22 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 16 ^ 43 1 12 24 14 14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 24 9 24 15 1 23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 18 ^ 57 0 4 23 21 13 19 15 21 7 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 7 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 ^ 55 1 6 25 3 12 19 6 2 4 24 17 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 14 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 23 ^ 53 0 1 10 11 11 4 12 11 20 3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 26 ^ 54 0 24 18 6 12 19 25 7 6 5 2 14 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 23 ^ 58 0 1 20 25 6 19 8 3 22 16 16 16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 19 ^ 52 1 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 21 16 22 ^ 56 1 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 25 2 25 22 9 15 16 26 5 12 1 7 4 24 7 14 20 1 4 7 3 10 10 15 6 13 6 22 6 20 22 2 26 9 6 14 1 16 3 24 12 ^ 52 0 24 17 12 14 18 18 9 9 11 22 13 9 2 22 15 20 20 18 8 13 13 21 8 11 5 26 8 19 17 4 2 15 26 13 24 26 11 16 9 1 8 18 21 6 1 8 1 16 4 20 23 5 ^ 54 0 24 10 11 12 10 10 25 1 11 25 10 3 26 26 20 15 11 19 16 17 3 16 12 25 15 9 23 1 2 24 8 10 18 2 9 5 4 17 16 9 12 20 20 1 3 11 5 9 3 17 9 17 24 20 ^ 49 1 3 4 16 2 10 1 25 5 22 16 6 21 19 21 23 15 9 9 21 17 11 1 15 17 23 24 11 7 10 26 15 8 22 22 18 26 11 17 5 26 7 23 19 3 24 17 2 19 8 ^ 49 0 26 21 12 5 18 22 20 7 15 6 4 5 20 13 10 23 18 16 25 18 15 2 20 14 24 22 17 3 15 16 1 10 2 12 2 21 1 21 21 4 18 13 1 24 18 23 17 19 23 ^ 50 1 19 9 26 25 23 23 14 13 13 20 12 13 4 21 10 22 21 22 1 12 12 7 13 16 18 8 9 4 3 10 18 12 4 5 19 19 12 24 13 18 1 22 8 1 17 18 24 3 22 21 ^ 48 1 7 19 26 13 26 6 26 6 18 12 5 26 17 18 19 22 10 12 8 23 11 17 23 25 5 5 11 4 13 7 18 4 19 23 3 13 15 4 3 9 24 14 5 25 21 22 18 25 ^ 53 1 12 15 14 16 10 14 9 19 7 16 3 23 4 26 18 5 16 21 24 2 8 8 8 7 11 13 14 7 9 12 18 11 10 7 20 12 14 19 11 21 21 22 19 13 10 16 19 14 7 8 16 20 7 ^ 49 0 3 9 23 18 7 26 16 22 21 21 5 14 11 2 2 16 22 11 26 7 22 23 5 23 10 4 22 24 19 20 9 16 10 24 4 19 26 4 25 4 8 17 7 7 2 23 11 18 19 ^ 49 0 23 6 10 9 1 9 14 19 5 6 6 25 12 11 21 26 12 3 8 20 8 21 18 25 25 14 4 11 24 23 4 14 3 17 26 22 26 2 15 9 8 25 19 12 23 17 20 17 10 ^ 54 0 4 23 20 17 21 14 14 9 18 11 18 2 18 4 2 22 25 15 18 10 23 8 21 26 7 14 10 6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 25 16 5 7 20 23 ^ 47 0 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 13 12 24 14 14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 15 ^ 51 1 9 24 15 1 23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 4 4 23 21 13 19 15 21 7 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 24 ^ 60 0 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 6 25 3 12 19 6 2 4 24 17 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 10 ^ 59 0 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 1 1 10 11 11 4 12 11 20 3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 8 ^ 50 0 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 24 18 6 12 19 25 7 6 5 2 14 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 14 ^ 60 0 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 1 20 25 6 19 8 3 22 16 16 16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 16 13 ^ 57 0 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 22 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 21 ^ 52 1 19 18 18 26 12 13 3 25 12 21 16 24 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 25 2 25 22 9 15 16 26 5 12 1 7 4 24 7 14 20 1 4 7 3 10 10 15 19 ^ 51 0 13 6 22 6 20 22 2 26 9 6 14 1 16 3 24 25 24 17 12 14 18 18 9 9 11 22 13 9 2 22 15 20 20 18 8 13 13 21 8 11 5 26 8 19 17 4 2 15 26 13 21 ^ 52 1 24 26 11 16 9 1 8 18 21 6 1 8 1 16 4 20 23 23 24 10 11 12 10 10 25 1 11 25 10 3 26 26 20 15 11 19 16 17 3 16 12 25 15 9 23 1 2 24 8 10 18 15 ^ 55 1 9 5 4 17 16 9 12 20 20 1 3 11 5 9 3 17 9 17 24 21 3 4 16 2 10 1 25 5 22 16 6 21 19 21 23 15 9 9 21 17 11 1 15 17 23 24 11 7 10 26 15 8 22 22 11 ^ 50 1 26 11 17 5 26 7 23 19 3 24 17 2 19 18 26 21 12 5 18 22 20 7 15 6 4 5 20 13 10 23 18 16 25 18 15 2 20 14 24 22 17 3 15 16 1 10 2 12 2 25 ^ 51 0 1 21 21 4 18 13 1 24 18 23 17 19 6 19 9 26 25 23 23 14 13 13 20 12 13 4 21 10 22 21 22 1 12 12 7 13 16 18 8 9 4 3 10 18 12 4 5 19 19 12 24 ^ 53 1 13 18 1 22 8 1 17 18 24 3 22 7 7 19 26 13 26 6 26 6 18 12 5 26 17 18 19 22 10 12 8 23 11 17 23 25 5 5 11 4 13 7 18 4 19 23 3 13 15 4 3 9 18 ^ 51 1 14 5 25 21 22 18 17 12 15 14 16 10 14 9 19 7 16 3 23 4 26 18 5 16 21 24 2 8 8 8 7 11 13 14 7 9 12 18 11 10 7 20 12 14 19 11 21 21 22 19 26 ^ 49 0 10 16 19 14 7 8 16 20 10 3 9 23 18 7 26 16 22 21 21 5 14 11 2 2 16 22 11 26 7 22 23 5 23 10 4 22 24 19 20 9 16 10 24 4 19 26 4 25 14 ^ 52 0 8 17 7 7 2 23 11 18 19 23 6 10 9 1 9 14 19 5 6 6 25 12 11 21 26 12 3 8 20 8 21 18 25 25 14 4 11 24 23 4 14 3 17 26 22 26 2 15 9 8 25 24 ^ 55 1 12 23 17 20 17 10 4 23 20 17 21 14 14 9 18 11 18 2 18 4 2 22 25 15 18 10 23 8 21 26 7 14 10 6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 15 ^ 49 0 16 5 7 20 22 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 13 12 24 14 14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 9 ^ 55 0 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 24 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 18 ^ 51 0 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 9 23 10 26 27 26 14 12 3 14 15 11 2 26 ^ 50 0 6 22 20 8 25 4 25 24 23 20 3 3 16 2 2 27 2 15 14 27 3 17 12 27 27 7 26 2 22 11 9 10 24 15 1 27 11 27 4 1 25 25 16 6 2 22 12 17 21 14 ^ 52 0 8 9 22 17 12 7 18 14 23 2 6 4 23 9 4 22 16 18 23 8 11 25 17 27 16 10 3 24 8 20 20 18 18 13 4 2 18 22 15 25 26 9 3 1 2 19 15 1 24 17 16 18 ^ 49 0 9 14 11 8 16 19 16 22 10 16 24 25 7 22 12 20 15 23 22 18 22 14 6 26 21 10 21 7 13 2 16 7 24 16 22 13 10 7 11 16 5 9 25 13 9 14 14 17 14 ^ 54 1 2 10 5 25 5 7 10 22 10 1 24 3 11 7 23 5 17 14 3 18 5 13 26 15 5 13 23 18 17 3 18 3 27 15 6 25 24 22 27 17 4 25 23 15 9 15 21 8 7 7 15 3 13 25 ^ 47 0 25 3 4 10 24 12 7 16 25 18 21 21 20 27 13 14 23 27 1 21 9 21 14 22 9 9 5 15 13 17 3 4 9 16 1 8 23 17 23 26 8 24 10 20 25 27 25 ^ 58 1 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 25 ^ 58 0 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 15 ^ 54 0 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 25 ^ 49 1 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 19 ^ 56 1 17 16 17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 22 ^ 51 1 3 26 22 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 13 ^ 48 1 14 19 26 27 25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 21 1 9 17 22 5 22 8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 25 ^ 52 0 2 6 1 1 26 18 13 5 10 18 10 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 17 10 15 2 20 25 26 23 25 12 16 15 9 18 15 19 21 16 26 11 18 20 26 ^ 53 0 6 22 7 8 8 12 2 21 18 12 11 5 19 3 19 27 18 25 22 22 23 16 2 1 20 16 14 22 6 15 22 1 21 6 6 10 2 26 12 11 6 27 14 7 20 26 20 17 7 19 5 23 14 ^ 61 0 16 12 7 15 17 7 5 11 12 15 7 1 10 10 8 4 2 4 17 4 11 17 26 23 24 4 5 12 5 1 6 9 6 8 27 5 11 11 24 24 13 17 2 24 26 19 11 22 21 2 2 14 21 13 1 23 10 25 8 15 13 ^ 52 0 19 23 2 9 26 6 23 13 5 24 12 21 11 14 4 12 10 12 22 4 3 20 17 10 13 16 9 10 27 9 12 13 20 10 12 23 23 11 19 13 25 22 8 1 5 16 20 9 19 9 24 26 ^ 51 0 12 15 6 21 27 22 26 24 18 9 15 8 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 24 14 8 13 12 19 22 ^ 56 0 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 6 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 9 23 17 ^ 50 0 26 27 26 14 12 3 14 15 11 2 12 6 22 20 8 25 4 25 24 23 20 3 3 16 2 2 27 2 15 14 27 3 17 12 27 27 7 26 2 22 11 9 10 24 15 1 27 11 27 21 ^ 52 0 1 25 25 16 6 2 22 12 17 21 12 8 9 22 17 12 7 18 14 23 2 6 4 23 9 4 22 16 18 23 8 11 25 17 27 16 10 3 24 8 20 20 18 18 13 4 2 18 22 15 25 10 ^ 52 0 9 3 1 2 19 15 1 24 17 16 18 9 14 11 8 16 19 16 22 10 16 24 25 7 22 12 20 15 23 22 18 22 14 6 26 21 10 21 7 13 2 16 7 24 16 22 13 10 7 11 16 13 ^ 53 1 9 25 13 9 14 14 17 25 2 10 5 25 5 7 10 22 10 1 24 3 11 7 23 5 17 14 3 18 5 13 26 15 5 13 23 18 17 3 18 3 27 15 6 25 24 22 27 17 4 25 23 15 15 ^ 52 1 15 21 8 7 7 15 3 13 22 25 3 4 10 24 12 7 16 25 18 21 21 20 27 13 14 23 27 1 21 9 21 14 22 9 9 5 15 13 17 3 4 9 16 1 8 23 17 23 26 8 24 14 ^ 58 0 20 25 27 3 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 18 ^ 60 0 5 18 7 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 25 ^ 55 0 16 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 27 ^ 51 1 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 15 ^ 57 0 17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 23 ^ 52 0 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 12 ^ 55 1 25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 21 1 9 17 22 5 22 8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 18 2 6 1 1 26 18 13 5 10 18 11 ^ 52 0 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 17 10 15 2 20 25 26 23 25 12 16 15 9 18 15 19 21 16 26 11 18 20 6 22 7 8 8 12 2 21 18 12 11 27 ^ 53 1 19 3 19 27 18 25 22 22 23 16 2 1 20 16 14 22 6 15 22 1 21 6 6 10 2 26 12 11 6 27 14 7 20 26 20 17 7 19 5 23 18 16 12 7 15 17 7 5 11 12 15 7 22 ^ 57 1 10 10 8 4 2 4 17 4 11 17 26 23 24 4 5 12 5 1 6 9 6 8 27 5 11 11 24 24 13 17 2 24 26 19 11 22 21 2 2 14 21 13 1 23 10 25 8 15 26 19 23 2 9 26 6 23 22 ^ 52 1 5 24 12 21 11 14 4 12 10 12 22 4 3 20 17 10 13 16 9 10 27 9 12 13 20 10 12 23 23 11 19 13 25 22 8 1 5 16 20 9 19 9 24 20 12 15 6 21 27 22 26 16 ^ 58 0 18 9 15 8 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 24 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 22 ^ 55 0 6 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 9 23 10 26 27 26 14 12 3 14 15 11 2 12 6 22 16 ^ 53 0 8 25 4 25 24 23 20 3 3 16 2 2 27 2 15 14 27 3 17 12 27 27 7 26 2 22 11 9 10 24 15 1 27 11 27 4 1 25 25 16 6 2 22 12 17 21 12 8 9 22 17 12 18 ^ 54 0 7 18 14 23 2 6 4 23 9 4 22 16 18 23 8 11 25 17 27 16 10 3 24 8 20 20 18 18 13 4 2 18 22 15 25 26 9 3 1 2 19 15 1 24 17 16 18 9 14 11 8 16 19 27 ^ 52 0 22 10 16 24 25 7 22 12 20 15 23 22 18 22 14 6 26 21 10 21 7 13 2 16 7 24 16 22 13 10 7 11 16 5 9 25 13 9 14 14 17 25 2 10 5 25 5 7 10 22 10 22 ^ 54 1 24 3 11 7 23 5 17 14 3 18 5 13 26 15 5 13 23 18 17 3 18 3 27 15 6 25 24 22 27 17 4 25 23 15 9 15 21 8 7 7 15 3 13 22 25 3 4 10 24 12 7 16 25 10 ^ 56 0 21 21 20 27 13 14 23 27 1 21 9 21 14 22 9 9 5 15 13 17 3 4 9 16 1 8 23 17 23 26 8 24 10 20 25 27 3 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 2 ^ 61 1 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 22 ^ 53 0 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 16 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 25 ^ 60 0 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 5 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 18 ^ 54 0 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 16 17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 24 ^ 57 0 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 22 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 10 ^ 48 0 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 27 25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 8 ^ 60 1 1 9 17 22 5 22 8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 18 2 6 1 1 26 18 13 5 10 18 10 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 17 10 15 2 20 25 26 23 21 ^ 54 1 12 16 15 9 18 15 19 21 16 26 11 18 20 6 22 7 8 8 12 2 21 18 12 11 5 19 3 19 27 18 25 22 22 23 16 2 1 20 16 14 22 6 15 22 1 21 6 6 10 2 26 12 11 24 ^ 60 0 27 14 7 20 26 20 17 7 19 5 23 18 16 12 7 15 17 7 5 11 12 15 7 1 10 10 8 4 2 4 17 4 11 17 26 23 24 4 5 12 5 1 6 9 6 8 27 5 11 11 24 24 13 17 2 24 26 19 11 22 ^ 55 0 21 2 2 14 21 13 1 23 10 25 8 15 26 19 23 2 9 26 6 23 13 5 24 12 21 11 14 4 12 10 12 22 4 3 20 17 10 13 16 9 10 27 9 12 13 20 10 12 23 23 11 19 13 25 13 ^ 55 0 8 1 5 16 20 9 19 9 24 20 12 15 6 21 27 22 26 24 18 9 15 8 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 16 ^ 60 0 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 6 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 10 ^ 55 1 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 25 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 22 ^ 52 1 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 17 ^ 57 0 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 22 18 6 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 25 5 ^ 57 0 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 24 5 15 21 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 9 ^ 55 0 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 27 5 2 6 6 27 20 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 28 ^ 59 1 17 5 9 10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 7 20 21 2 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 25 ^ 55 0 3 5 16 16 22 2 13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 15 18 4 19 10 27 9 4 25 13 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 18 ^ 53 1 23 19 4 28 3 20 18 9 7 15 4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 10 13 2 19 21 6 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 10 ^ 47 0 1 3 28 11 27 25 12 8 26 26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 27 27 25 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 24 ^ 55 1 25 27 16 28 22 24 1 1 11 7 24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 19 23 1 26 20 17 17 1 16 24 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 26 ^ 47 1 14 4 21 26 23 7 8 27 23 23 22 19 24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 23 27 4 16 20 18 12 20 15 19 16 18 20 27 11 11 17 24 18 16 ^ 50 0 19 1 25 23 2 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 17 7 25 6 23 24 14 25 12 5 13 25 ^ 60 0 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 2 9 25 18 17 8 2 14 4 19 22 ^ 54 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 9 23 20 3 28 21 ^ 56 0 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 8 3 17 28 18 13 ^ 58 0 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 5 24 23 11 ^ 62 1 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 3 7 5 8 9 24 ^ 50 1 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 17 ^ 60 1 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 17 ^ 52 0 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 19 ^ 57 1 18 6 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 12 ^ 67 1 5 15 21 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 27 5 2 6 6 27 2 ^ 56 1 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 7 20 21 24 ^ 60 1 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 6 3 5 16 16 22 2 13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 15 18 4 19 10 27 9 4 25 27 ^ 51 0 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 3 23 19 4 28 3 20 18 9 7 15 4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 10 13 2 19 21 23 ^ 49 1 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 5 1 3 28 11 27 25 12 8 26 26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 27 27 9 ^ 56 0 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 11 25 27 16 28 22 24 1 1 11 7 24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 19 23 1 26 20 17 17 1 16 16 ^ 51 0 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 27 14 4 21 26 23 7 8 27 23 23 22 19 24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 23 27 4 16 20 18 12 22 ^ 51 0 15 19 16 18 20 27 11 11 17 24 18 1 19 1 25 23 2 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 16 ^ 59 0 7 25 6 23 24 14 25 12 5 13 26 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 10 ^ 59 0 25 2 9 25 18 17 8 2 14 4 19 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 7 ^ 56 1 17 9 23 20 3 28 27 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 ^ 57 1 23 8 3 17 28 18 10 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 18 ^ 63 0 1 9 9 10 5 24 23 18 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 16 ^ 52 1 16 3 7 5 8 9 26 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 28 ^ 60 0 21 9 15 13 25 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 20 ^ 54 1 14 14 15 18 13 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 11 ^ 58 0 9 15 22 18 6 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 27 ^ 64 1 21 24 5 15 21 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 27 20 ^ 58 1 2 6 6 27 20 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 28 ^ 62 0 20 21 2 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 6 3 5 16 16 22 2 13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 15 18 4 19 10 27 9 4 26 ^ 52 0 13 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 3 23 19 4 28 3 20 18 9 7 15 4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 10 13 2 19 21 27 ^ 49 1 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 5 1 3 28 11 27 25 12 8 26 26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 27 27 26 ^ 57 0 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 11 25 27 16 28 22 24 1 1 11 7 24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 19 23 1 26 20 17 17 1 16 24 9 ^ 52 1 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 27 14 4 21 26 23 7 8 27 23 23 22 19 24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 23 27 4 16 20 18 12 20 19 ^ 52 1 19 16 18 20 27 11 11 17 24 18 1 19 1 25 23 2 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 17 7 24 ^ 59 0 6 23 24 14 25 12 5 13 26 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 26 ^ 59 0 9 25 18 17 8 2 14 4 19 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 21 ^ 56 1 23 20 3 28 27 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 20 ^ 60 0 3 17 28 18 10 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 21 ^ 60 0 24 23 18 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 25 ^ 53 1 7 5 8 9 26 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 24 ^ 62 1 13 25 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 ^ 54 0 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 22 18 13 ^ 58 0 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 24 5 15 26 ^ 67 1 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 27 5 2 6 6 27 20 24 21 12 ^ 62 0 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 7 20 21 2 11 12 3 15 12 4 1 27 18 ^ 61 1 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 8 9 26 ^ 55 1 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 28 ^ 52 1 24 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 27 ^ 65 0 3 2 2 17 21 13 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 2 16 27 16 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 12 ^ 55 0 1 9 15 10 12 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 27 21 17 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 24 ^ 53 1 22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 8 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 11 ^ 55 0 25 10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 26 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 20 ^ 58 0 5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 4 5 27 5 19 21 5 6 11 29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 12 ^ 54 0 5 26 6 21 29 3 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 26 29 24 19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 28 ^ 56 0 3 6 19 28 17 11 1 9 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 24 28 8 14 9 3 14 18 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 25 ^ 49 0 29 21 9 18 28 25 11 3 16 4 21 25 3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 27 26 21 25 21 18 9 24 16 22 5 21 7 7 27 4 20 23 13 27 10 27 ^ 58 1 29 7 19 13 13 8 19 20 18 2 19 22 29 3 10 6 9 13 24 17 16 9 20 21 27 2 19 7 8 26 25 12 2 14 3 1 1 16 12 20 28 24 12 5 24 25 20 1 12 25 9 2 6 20 15 14 29 20 ^ 56 0 21 28 1 17 6 17 27 1 2 10 16 19 5 14 10 27 11 17 3 29 14 27 17 5 2 18 20 11 27 18 22 27 22 9 8 18 3 14 10 5 2 24 18 23 21 26 8 22 8 1 6 27 27 15 29 18 ^ 64 0 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 2 12 10 5 10 15 25 ^ 62 1 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 29 17 7 16 22 ^ 55 1 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 7 29 28 15 ^ 52 0 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 11 12 14 12 28 ^ 62 0 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 18 ^ 58 0 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 16 ^ 56 0 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 23 ^ 64 1 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 2 16 27 16 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 28 1 9 15 10 24 ^ 54 0 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 27 21 17 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 7 22 3 27 29 ^ 54 1 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 8 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 10 25 10 1 28 27 ^ 60 0 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 26 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 28 5 14 2 6 4 2 9 22 15 22 ^ 54 1 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 4 5 27 5 19 21 5 6 11 29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 6 5 26 6 21 29 28 ^ 57 1 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 26 29 24 19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 19 28 17 11 1 9 23 ^ 54 0 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 24 28 8 14 9 3 14 18 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 4 29 21 9 18 28 27 ^ 52 1 11 3 16 4 21 25 3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 27 26 21 25 21 18 9 24 16 22 5 21 7 7 27 4 20 23 13 27 10 23 29 7 19 13 13 8 19 20 23 ^ 61 0 2 19 22 29 3 10 6 9 13 24 17 16 9 20 21 27 2 19 7 8 26 25 12 2 14 3 1 1 16 12 20 28 24 12 5 24 25 20 1 12 25 9 2 6 20 15 14 29 18 21 28 1 17 6 17 27 1 2 10 16 19 ^ 57 1 5 14 10 27 11 17 3 29 14 27 17 5 2 18 20 11 27 18 22 27 22 9 8 18 3 14 10 5 2 24 18 23 21 26 8 22 8 1 6 27 27 15 29 20 2 29 22 8 16 20 4 12 9 6 12 16 24 ^ 64 0 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 2 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 10 ^ 63 1 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 29 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 ^ 56 1 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 7 29 28 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 29 ^ 54 0 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 11 12 14 12 18 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 22 ^ 63 0 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 8 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 19 ^ 59 0 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 24 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 10 ^ 62 0 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 2 16 27 29 ^ 62 0 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 28 1 9 15 10 12 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 27 21 18 ^ 54 1 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 7 22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 17 ^ 52 0 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 10 25 10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 13 ^ 68 0 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 28 5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 4 5 27 5 19 21 5 6 11 19 ^ 54 1 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 6 5 26 6 21 29 3 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 26 29 24 19 17 24 ^ 59 0 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 19 28 17 11 1 9 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 24 28 8 14 9 3 14 16 ^ 53 0 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 4 29 21 9 18 28 25 11 3 16 4 21 25 3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 27 26 21 25 21 18 9 24 16 17 ^ 59 0 5 21 7 7 27 4 20 23 13 27 10 23 29 7 19 13 13 8 19 20 18 2 19 22 29 3 10 6 9 13 24 17 16 9 20 21 27 2 19 7 8 26 25 12 2 14 3 1 1 16 12 20 28 24 12 5 24 25 19 ^ 60 0 1 12 25 9 2 6 20 15 14 29 18 21 28 1 17 6 17 27 1 2 10 16 19 5 14 10 27 11 17 3 29 14 27 17 5 2 18 20 11 27 18 22 27 22 9 8 18 3 14 10 5 2 24 18 23 21 26 8 22 13 ^ 62 0 1 6 27 27 15 29 20 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 24 ^ 67 0 14 17 2 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 14 ^ 58 1 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 7 29 11 ^ 55 0 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 11 12 14 12 18 27 10 ^ 65 0 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 8 9 5 25 19 20 ^ 59 1 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 24 9 17 11 28 12 23 ^ 61 0 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 5 9 21 28 9 1 13 2 21 8 29 ^ 68 0 1 3 27 13 18 19 4 15 12 5 2 16 27 16 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 28 1 9 15 10 12 7 25 11 25 2 27 6 6 18 4 13 1 4 11 26 ^ 54 1 17 6 29 21 24 27 21 17 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 7 22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 20 ^ 52 1 16 1 21 23 28 23 18 8 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 10 25 10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 12 ^ 67 0 7 15 18 11 5 17 20 26 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 28 5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 19 ^ 58 0 5 27 5 19 21 5 6 11 29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 6 5 26 6 21 29 3 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 27 ^ 57 0 29 24 19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 19 28 17 11 1 9 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 25 ^ 52 0 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 18 ^ 62 0 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 29 30 7 ^ 62 0 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 7 17 16 26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 27 5 19 15 ^ 57 0 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 1 20 11 1 30 22 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 25 ^ 61 1 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 16 19 20 17 10 17 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 22 ^ 58 1 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 27 19 7 20 21 25 5 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 17 ^ 62 1 23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 2 6 8 5 14 11 21 9 16 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 21 ^ 57 1 25 11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 21 11 4 10 23 25 7 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 21 ^ 65 0 2 2 24 17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 20 12 23 1 26 7 9 19 6 16 3 8 26 21 10 26 23 24 28 16 12 14 25 22 16 15 ^ 53 0 21 24 27 30 15 10 15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 2 10 16 6 5 7 23 19 11 28 22 21 1 24 19 7 26 18 30 26 ^ 58 0 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 22 ^ 59 0 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 25 ^ 55 1 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 21 ^ 57 0 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 12 19 11 10 6 26 14 22 24 30 2 ^ 56 1 11 12 2 12 17 23 8 8 12 28 13 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 3 23 11 6 29 25 23 26 17 23 ^ 61 1 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 14 3 1 18 10 20 27 21 8 6 24 30 ^ 54 0 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 7 ^ 63 1 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 10 2 5 29 12 ^ 63 1 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 29 30 17 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 7 17 16 26 3 19 3 5 2 29 16 17 ^ 60 1 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 27 5 19 28 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 1 20 11 1 30 22 23 15 26 6 ^ 56 0 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 11 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 16 19 20 17 10 17 21 20 11 ^ 64 1 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 4 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 27 19 7 20 21 25 5 30 ^ 63 1 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 2 6 8 5 14 11 21 9 29 ^ 57 0 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 21 11 4 10 23 25 6 ^ 68 0 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 20 12 23 1 26 7 9 19 6 30 ^ 54 1 3 8 26 21 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 2 10 16 6 27 ^ 56 0 7 23 19 11 28 22 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 9 ^ 58 0 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 29 ^ 65 0 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 20 ^ 55 0 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 30 ^ 57 1 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 13 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 30 ^ 59 0 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 18 ^ 56 0 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 7 ^ 62 0 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 ^ 62 1 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 29 30 17 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 26 ^ 62 0 17 16 26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 27 5 19 28 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 19 ^ 56 1 20 11 1 30 22 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 11 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 22 ^ 66 1 16 19 20 17 10 17 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 4 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 24 ^ 62 0 19 7 20 21 25 5 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 7 ^ 59 0 6 8 5 14 11 21 9 16 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 26 ^ 70 0 11 4 10 23 25 7 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 20 12 23 1 26 7 ^ 54 1 9 19 6 16 3 8 26 21 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 27 ^ 58 1 10 16 6 5 7 23 19 11 28 22 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 28 ^ 58 1 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 22 ^ 65 1 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 20 ^ 53 0 17 30 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 15 ^ 61 0 8 2 4 12 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 13 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 20 ^ 60 0 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 14 20 ^ 56 0 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 23 ^ 62 0 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 23 ^ 64 1 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 29 30 17 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 7 17 18 ^ 65 0 26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 27 5 19 28 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 1 20 11 1 30 5 ^ 57 0 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 11 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 16 19 20 17 10 25 ^ 66 1 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 4 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 27 19 7 20 21 25 20 ^ 65 1 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 2 6 8 5 14 11 21 9 16 28 ^ 59 1 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 21 11 4 10 23 25 7 5 11 23 ^ 70 0 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 20 12 23 1 26 7 9 19 6 16 3 8 26 25 ^ 56 0 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 2 10 16 6 5 7 23 19 11 28 24 ^ 59 1 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 18 19 13 ^ 63 1 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 20 ^ 59 1 15 20 8 3 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 23 ^ 61 0 16 21 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 30 13 18 2 3 8 2 17 8 24 28 ^ 69 0 22 2 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 25 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 1 3 3 4 16 13 17 6 16 14 28 ^ 62 0 3 20 3 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 22 4 17 9 27 ^ 60 0 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 19 22 9 15 25 ^ 64 0 31 7 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 27 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 27 2 16 10 31 ^ 60 0 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 19 ^ 62 0 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 24 ^ 62 0 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 21 ^ 56 1 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 11 ^ 54 0 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 28 27 15 18 14 25 23 ^ 59 1 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 25 ^ 58 0 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 24 ^ 56 1 11 14 15 24 15 12 9 22 16 16 24 13 2 26 24 29 26 15 13 21 24 20 10 10 22 23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 19 24 12 31 8 30 31 9 28 12 3 26 29 8 ^ 65 0 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 15 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 10 11 29 25 17 27 23 ^ 60 0 26 3 23 14 4 30 27 23 24 21 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 31 29 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 11 24 24 ^ 58 1 11 15 29 29 3 31 18 12 17 31 19 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 30 30 6 10 18 5 9 10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 16 28 ^ 61 1 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 30 13 18 2 3 8 2 17 8 24 30 22 29 ^ 70 0 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 25 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 1 3 3 4 16 13 17 6 16 14 24 3 20 21 ^ 62 1 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 22 4 17 9 4 21 23 21 ^ 62 1 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 19 22 9 15 10 31 7 18 29 7 ^ 66 1 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 27 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 21 ^ 62 1 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 8 ^ 62 1 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 21 ^ 65 0 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 31 ^ 55 1 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 27 ^ 53 1 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 21 ^ 61 0 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 8 14 7 15 19 ^ 59 1 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 16 24 13 23 ^ 57 0 26 24 29 26 15 13 21 24 20 10 10 22 23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 19 24 12 31 8 30 31 9 28 12 3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 16 ^ 61 1 12 4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 15 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 10 11 29 25 17 27 22 26 3 23 14 4 30 27 23 24 31 ^ 61 1 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 31 29 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 11 24 27 11 15 29 29 3 31 18 12 17 31 12 ^ 60 1 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 30 30 6 10 18 5 9 10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 9 18 30 17 4 6 31 26 16 18 ^ 67 1 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 30 13 18 2 3 8 2 17 8 24 30 22 2 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 28 ^ 69 1 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 1 3 3 4 16 13 17 6 16 14 24 3 20 3 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 28 ^ 62 1 26 26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 22 4 17 9 4 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 26 ^ 70 1 4 3 9 9 14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 19 22 9 15 10 31 7 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 17 ^ 60 1 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 7 ^ 66 0 26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 17 ^ 64 1 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 27 ^ 64 0 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 13 ^ 58 0 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 28 ^ 57 0 30 21 22 5 27 12 30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 26 ^ 59 0 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 19 ^ 59 0 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 16 24 13 2 26 24 29 26 15 13 21 24 20 10 10 22 23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 31 ^ 66 1 24 12 31 8 30 31 9 28 12 3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 15 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 21 ^ 59 0 20 28 31 6 22 10 11 29 25 17 27 22 26 3 23 14 4 30 27 23 24 21 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 31 29 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 26 ^ 59 0 21 16 11 2 23 18 27 29 18 9 11 24 27 11 15 29 29 3 31 18 12 17 31 19 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 30 30 6 10 18 5 9 10 26 9 17 2 30 24 ^ 61 0 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 25 ^ 74 0 13 18 2 3 8 2 17 8 24 30 22 2 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 25 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 1 3 3 4 16 16 ^ 64 1 17 6 16 14 24 3 20 3 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 22 27 ^ 65 0 17 9 4 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 19 22 9 15 10 31 1 ^ 68 1 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 27 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 ^ 63 0 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 24 ^ 64 1 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 16 31 5 ^ 67 0 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 21 ^ 58 0 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 22 ^ 60 0 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 22 ^ 60 1 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 31 ^ 58 0 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 16 24 13 2 26 24 29 26 15 13 21 24 20 10 10 25 ^ 65 0 23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 19 24 12 31 8 30 31 9 28 12 3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 21 ^ 60 1 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 10 11 29 25 17 27 22 26 3 23 14 4 30 27 23 24 21 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 31 11 ^ 64 1 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 11 24 27 11 15 29 29 3 31 18 12 17 31 19 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 25 ^ 64 0 30 6 10 18 5 9 10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 31 ^ 60 0 28 5 24 16 10 27 28 19 29 19 22 10 23 17 25 7 26 5 5 27 1 20 24 13 27 16 24 32 31 5 12 21 13 6 11 21 20 15 3 14 18 32 2 9 6 10 13 23 16 17 3 20 19 27 29 21 5 11 28 14 ^ SHS Type 2 Strings 60 1 16 13 19 5 16 14 27 2 22 7 5 28 15 18 25 17 13 12 29 24 21 29 25 16 5 17 22 24 8 8 18 3 13 10 28 3 23 28 12 8 3 25 5 25 24 7 14 30 27 32 30 23 8 15 27 28 13 8 12 21 ^ 86 1 33 5 40 26 3 19 12 36 43 5 35 37 5 14 11 45 35 16 10 8 32 4 15 35 26 2 39 22 37 22 30 29 28 36 45 14 36 4 29 37 30 34 36 20 9 42 29 9 11 11 18 42 13 6 20 42 20 30 22 35 34 6 14 41 19 30 17 35 33 26 41 15 5 44 39 8 20 3 44 32 15 18 10 15 10 36 ^ 112 0 10 44 24 53 35 22 40 20 15 51 22 18 22 42 6 54 49 38 21 7 13 30 16 7 52 16 22 13 38 7 11 44 33 9 25 13 37 42 14 45 53 30 38 5 25 5 35 38 22 28 10 29 52 31 39 35 23 5 17 14 31 46 5 41 54 43 33 13 23 46 45 3 46 3 55 15 6 53 28 52 22 27 45 32 53 51 15 37 15 49 36 35 35 15 3 13 22 25 3 4 10 24 12 7 44 25 18 21 21 20 55 24 ^ 123 1 43 9 1 52 4 21 49 61 18 50 23 13 46 62 23 45 62 9 56 18 23 31 8 30 27 36 13 38 4 58 53 47 24 18 41 58 19 12 18 52 42 29 44 45 26 63 34 32 41 64 15 26 55 19 2 49 6 30 53 13 54 12 53 37 12 37 29 60 53 21 47 42 45 52 40 10 28 47 43 17 16 17 61 36 12 34 60 37 13 52 58 37 39 29 34 11 45 8 36 1 50 50 5 51 13 15 32 51 33 61 16 31 50 58 63 16 5 30 17 24 10 26 52 ^ 144 1 64 62 63 30 15 1 35 28 16 40 20 14 50 33 19 38 30 27 55 10 16 46 47 7 55 12 53 26 56 33 29 55 25 17 48 43 21 43 18 24 63 27 68 46 38 33 35 10 18 11 27 5 9 58 35 70 36 36 39 47 2 10 66 47 5 18 21 44 71 51 57 3 22 7 56 55 28 25 14 40 16 24 48 37 66 50 24 45 18 39 53 29 64 60 26 50 6 47 61 46 44 60 17 4 58 45 26 20 26 32 8 7 68 37 3 24 44 47 64 54 71 57 12 68 27 58 29 54 43 42 60 13 14 56 49 1 32 9 61 43 36 33 20 59 ^ 166 0 7 38 57 33 61 73 7 64 1 49 35 76 14 27 21 45 68 38 58 73 13 72 47 73 33 8 66 23 38 4 56 77 47 10 71 13 20 31 41 6 51 3 18 17 61 47 14 48 76 46 28 34 43 1 56 4 25 7 65 41 1 34 37 23 59 59 27 26 13 15 14 75 60 14 1 28 59 26 65 61 16 23 17 28 6 19 2 35 49 30 29 48 2 63 73 59 1 3 76 41 11 19 18 43 54 63 67 51 4 9 78 60 8 72 31 35 77 54 58 20 36 58 51 76 40 20 37 49 3 75 1 29 20 57 64 22 25 6 25 59 32 43 58 40 51 77 1 2 36 10 12 28 39 11 46 2 41 27 27 53 76 13 66 69 76 28 ^ 186 1 5 73 38 30 30 48 21 75 80 40 21 8 53 9 26 30 34 81 71 71 51 23 75 33 41 23 32 5 8 66 40 72 40 16 66 45 14 48 34 21 41 27 3 55 27 37 23 41 65 4 57 51 74 22 19 75 42 16 19 46 16 10 48 20 19 37 41 14 57 9 17 55 38 5 60 7 46 20 43 36 39 52 20 10 62 45 23 46 7 35 75 29 70 35 36 34 25 12 15 84 26 10 6 71 29 79 33 32 25 59 76 82 64 58 7 8 19 41 74 2 53 65 24 1 55 51 36 21 79 28 5 17 41 36 63 51 18 48 25 46 45 36 77 76 22 57 14 44 63 56 45 56 20 1 64 49 9 12 28 30 72 82 73 33 3 22 30 43 56 67 62 2 57 13 50 20 57 38 43 61 9 8 57 65 76 9 ^ 183 1 54 34 83 10 33 51 86 81 82 69 18 8 22 64 19 86 62 58 33 37 17 34 5 29 83 42 76 50 54 66 39 9 1 36 43 17 65 6 35 56 72 71 83 88 10 1 8 87 22 6 21 78 25 89 43 62 40 55 85 31 89 74 63 46 28 24 26 31 17 7 8 27 19 12 85 17 20 27 77 10 2 54 80 17 52 74 76 69 78 11 20 80 4 29 24 85 75 18 39 23 70 83 29 57 67 72 70 33 4 15 46 42 2 69 13 53 33 69 64 33 64 14 40 69 59 78 71 19 85 16 65 38 82 55 40 56 40 24 84 29 25 44 68 13 85 76 64 32 18 25 45 23 6 80 31 30 30 58 14 13 72 57 14 41 28 52 73 26 76 83 56 54 2 36 11 65 66 38 50 8 41 88 77 ^ 200 1 25 57 40 46 78 57 34 78 61 36 66 57 38 80 22 32 68 71 30 74 37 81 66 77 66 55 2 51 24 93 61 40 68 45 61 12 63 24 89 59 52 72 43 20 20 69 36 40 88 46 9 62 55 77 84 20 18 6 77 15 52 39 75 3 26 4 85 17 62 29 11 92 46 58 29 59 28 42 80 71 96 2 49 85 37 63 4 61 14 2 53 87 25 86 6 75 76 93 41 39 93 92 42 56 41 63 26 28 18 77 11 50 78 79 1 12 12 91 29 13 58 5 56 92 66 59 4 39 47 95 5 5 62 33 13 80 69 60 43 51 22 30 32 42 5 38 3 50 7 48 90 56 96 68 47 41 61 60 96 20 14 4 19 19 23 25 13 9 38 52 17 11 96 48 19 25 88 42 7 74 59 48 70 55 24 18 28 44 46 3 24 38 56 19 96 22 50 60 17 96 ^ 195 1 25 51 45 35 66 19 61 60 9 31 93 64 70 30 42 86 53 1 71 46 42 22 38 96 10 99 34 76 26 55 73 63 63 97 23 92 81 64 46 1 30 31 35 86 91 88 64 87 16 37 69 84 94 60 100 3 47 52 8 71 87 57 29 76 43 18 45 46 15 65 12 44 42 66 60 15 68 19 58 39 62 76 9 92 101 57 32 4 34 15 41 62 32 89 71 43 35 31 41 21 17 82 33 96 27 62 29 82 57 46 62 15 24 99 37 83 40 52 46 56 80 98 3 91 74 6 27 7 58 94 10 41 79 97 84 77 74 26 99 95 61 19 17 24 55 15 85 84 30 45 93 44 100 44 39 59 46 18 95 3 41 15 82 77 16 48 18 51 83 20 82 60 53 53 12 99 92 54 5 99 51 39 100 61 2 31 52 49 86 94 16 78 84 91 42 ^ 212 0 56 98 16 98 78 22 72 33 103 104 52 84 12 65 15 85 101 97 84 31 51 26 100 100 38 80 13 2 78 7 24 44 84 103 27 7 28 16 33 99 25 103 54 14 42 62 87 92 27 22 42 5 52 100 84 73 72 63 24 48 56 52 23 5 17 76 31 1 95 58 43 60 50 62 30 23 35 79 20 35 3 72 32 45 51 87 41 84 27 79 77 70 102 15 54 15 100 8 52 69 105 3 30 84 42 93 66 89 69 74 24 33 42 97 4 38 99 106 13 93 6 106 74 100 54 45 21 59 56 37 9 50 32 75 79 31 77 9 61 1 8 68 6 60 81 7 100 99 14 61 48 25 73 26 70 72 94 3 11 98 31 5 67 7 39 92 73 88 101 32 105 34 82 81 11 72 48 10 59 71 51 71 35 33 27 49 49 19 98 47 43 75 64 17 15 24 94 49 4 84 58 58 74 39 47 104 82 5 63 69 90 19 ^ 236 1 29 79 41 40 72 51 12 92 34 52 44 69 104 21 97 89 96 48 21 4 61 40 28 67 34 23 85 44 22 62 52 33 84 23 30 73 74 4 79 12 81 47 80 53 47 89 40 19 80 62 34 61 29 41 95 43 1 70 63 55 53 18 19 13 48 10 19 89 49 4 52 53 56 76 10 8 104 77 15 28 38 75 109 3 85 90 8 40 8 93 90 43 39 14 60 17 36 78 56 105 80 35 75 36 58 82 50 100 98 45 74 13 66 95 72 71 95 34 14 98 72 33 38 37 52 6 14 107 59 3 29 61 67 98 92 5 93 17 98 36 87 41 75 71 57 88 17 25 91 84 3 58 20 92 69 51 50 36 31 14 25 18 30 18 1 41 104 30 82 59 87 70 34 96 28 47 62 81 103 109 103 100 7 17 16 104 1 12 34 5 102 42 16 22 71 39 5 73 45 45 54 41 13 2 26 41 22 100 109 30 44 4 90 108 53 38 104 68 28 56 47 51 94 22 7 81 85 26 50 9 72 98 54 59 96 52 ^ 232 1 92 72 47 37 33 38 92 17 8 28 88 22 62 69 32 89 75 3 72 96 85 13 105 24 38 37 94 115 83 72 108 114 24 93 76 103 60 99 102 9 43 10 59 95 46 33 93 15 26 69 44 2 86 107 55 45 61 65 92 66 9 55 39 70 83 29 98 67 13 111 15 20 31 62 8 2 51 20 19 33 44 14 115 71 112 97 10 41 28 53 51 26 57 15 38 98 55 106 22 56 31 50 95 107 110 84 70 10 108 96 73 100 25 36 55 88 71 63 96 30 90 96 79 22 7 30 23 28 59 89 8 51 99 47 86 34 18 43 65 98 104 107 49 7 79 71 8 57 21 29 80 2 74 78 44 57 9 61 22 13 68 52 91 74 98 43 30 58 68 95 101 72 102 76 42 99 108 47 25 73 27 104 34 59 52 36 104 20 98 14 97 4 50 46 106 83 17 22 105 79 77 46 39 15 113 20 37 100 106 65 66 76 7 12 72 35 8 22 50 40 68 101 23 54 96 44 51 87 18 6 46 110 ^ 245 0 70 30 81 46 53 119 85 6 104 47 92 72 70 5 70 15 115 68 105 33 97 13 85 106 14 61 29 22 86 45 57 69 91 38 38 28 66 13 60 95 103 3 15 5 113 38 23 62 5 65 94 107 73 104 37 47 102 117 3 78 35 7 95 56 78 45 52 28 46 43 37 32 53 19 55 29 47 97 76 115 83 71 11 45 62 73 99 116 2 24 116 7 28 41 2 29 37 52 23 5 118 79 31 57 89 61 24 101 78 50 93 73 41 7 33 45 47 24 1 48 73 36 3 25 87 46 28 108 54 68 53 67 119 28 36 118 104 42 88 27 112 4 74 85 1 63 39 97 71 74 75 76 10 49 12 79 11 50 103 118 94 117 118 37 27 12 94 60 28 51 47 82 110 17 15 105 23 52 43 12 21 22 81 41 12 74 90 42 108 117 98 67 4 69 44 76 105 38 101 21 80 70 10 111 23 110 32 101 83 91 101 31 5 3 83 76 15 90 57 74 95 46 33 112 62 63 54 63 49 59 4 64 40 68 110 74 105 91 86 102 27 55 34 88 55 ^ 240 0 55 79 75 84 113 22 4 113 109 31 33 17 96 11 29 63 98 103 107 116 34 14 9 95 38 18 51 75 33 109 118 55 66 4 76 7 75 70 82 74 23 1 26 69 40 112 99 47 65 31 70 119 52 103 88 85 86 28 16 12 76 25 22 78 64 21 86 27 61 77 72 108 2 18 106 119 121 54 16 85 72 2 73 26 88 66 60 80 35 24 117 63 24 44 67 52 122 119 33 72 16 99 98 69 54 19 42 28 53 114 32 117 81 100 57 49 123 56 21 68 80 53 95 1 45 95 107 98 87 1 27 24 99 116 16 67 1 113 91 84 25 40 25 72 3 28 90 87 112 80 16 117 45 77 36 90 105 59 88 122 64 108 108 71 98 18 50 115 93 105 77 35 6 46 55 47 102 4 26 87 111 120 81 113 4 57 105 3 84 94 115 61 3 121 72 71 24 62 14 60 99 61 96 103 51 107 6 65 81 114 83 121 109 49 104 30 73 82 92 94 9 8 11 98 19 10 55 97 22 97 95 88 67 15 20 39 65 13 123 77 ^ 253 1 45 7 15 24 51 5 98 115 24 49 90 104 117 66 128 94 64 80 12 43 91 46 111 59 58 77 30 14 88 60 123 68 41 44 68 40 104 118 41 43 93 90 105 92 16 127 26 54 125 114 79 71 24 48 21 25 118 40 103 49 91 44 67 65 25 119 109 18 48 23 69 112 38 61 64 87 84 104 119 110 122 92 22 1 8 83 34 100 32 62 41 46 112 34 102 76 56 39 4 127 30 13 19 110 124 7 16 128 95 4 124 11 104 116 126 49 95 3 55 96 70 90 101 4 122 96 75 118 39 128 99 92 18 42 20 87 83 35 75 111 61 67 71 28 101 9 56 34 105 95 71 23 73 71 26 57 15 23 76 55 99 89 128 98 117 68 43 88 62 38 62 39 2 83 36 15 26 60 128 96 73 74 10 1 12 42 22 2 77 33 33 32 57 13 14 82 57 12 39 3 58 80 14 87 85 44 69 109 19 117 67 68 44 63 106 37 88 64 82 56 37 89 4 126 55 98 114 84 99 91 43 92 21 26 58 84 102 75 116 124 5 101 5 97 46 109 15 29 79 72 93 92 110 ^ 289 1 83 5 76 20 32 15 10 1 103 18 22 116 98 9 51 104 102 44 33 15 12 24 31 89 1 6 28 101 8 64 72 106 30 5 52 89 111 39 108 64 85 17 57 124 22 105 78 115 3 40 108 66 108 77 128 103 44 35 38 13 95 10 111 63 98 117 61 51 126 69 96 70 70 59 39 13 97 33 112 2 77 7 123 70 83 29 66 67 49 79 19 104 115 14 60 2 55 40 71 33 28 114 51 91 17 46 45 128 57 87 62 25 115 38 50 55 90 74 8 51 102 79 43 94 36 122 94 12 41 36 25 104 91 24 7 99 80 30 126 32 63 122 107 114 27 28 79 41 12 35 51 115 122 70 22 79 65 2 88 27 17 59 15 23 44 57 5 65 6 26 78 80 125 93 84 100 45 22 129 68 36 111 74 118 11 50 42 120 47 21 8 86 112 26 67 60 99 45 93 47 8 38 59 52 56 124 20 82 18 117 24 18 46 106 19 117 26 41 47 45 130 7 15 1 4 5 100 10 85 50 44 11 48 92 119 108 42 118 24 20 69 107 90 96 48 103 7 2 90 50 18 130 126 45 106 17 35 25 102 68 23 68 120 58 41 34 75 103 20 45 117 37 61 73 34 62 1 125 58 74 21 21 129 7 86 110 76 66 124 ^ 263 1 100 135 7 75 23 5 81 110 31 118 29 1 62 11 41 88 109 119 102 37 3 30 123 47 31 56 134 29 124 116 118 99 21 56 77 91 23 37 135 81 44 51 67 95 51 133 30 57 67 116 122 48 100 7 132 97 106 69 93 4 95 125 102 103 119 81 57 133 96 37 118 50 117 113 81 127 17 45 103 32 121 129 60 43 65 127 30 36 132 110 52 53 35 71 12 76 22 72 130 112 99 76 26 21 73 63 63 97 23 58 115 132 114 1 132 31 35 18 23 54 30 53 118 37 35 84 94 60 100 3 47 18 110 105 87 57 63 76 43 52 45 46 49 65 12 10 42 66 60 117 34 19 92 5 28 76 9 126 101 125 32 38 34 15 7 62 32 21 3 43 69 31 109 123 51 116 135 130 129 130 63 14 57 80 62 15 126 31 105 83 108 120 80 124 46 98 105 91 6 6 27 7 58 128 78 7 79 63 84 77 74 128 65 61 95 121 17 24 123 117 51 50 64 79 59 44 134 78 73 59 114 18 27 3 109 49 82 43 118 116 52 119 15 122 82 26 87 53 114 133 92 88 39 99 17 107 134 95 104 31 52 49 94 ^ 286 0 120 16 104 136 117 82 138 32 65 114 119 137 121 8 12 46 126 26 119 73 130 60 76 113 100 14 133 26 116 34 120 80 95 84 53 15 24 44 51 4 10 23 77 24 99 66 37 54 63 42 136 21 34 76 5 17 128 101 1 59 40 113 112 32 97 31 93 105 79 91 18 39 1 103 132 51 68 124 111 13 97 43 128 69 84 85 72 15 12 26 87 16 16 92 101 13 77 4 118 89 103 56 42 16 60 44 39 126 46 18 83 93 41 105 3 82 106 115 91 6 4 54 115 15 120 109 113 48 41 9 95 20 62 67 105 111 25 132 7 116 46 138 44 83 61 124 131 35 107 6 109 81 114 67 41 137 77 56 74 73 34 12 14 69 52 11 98 47 54 83 81 6 1 15 88 35 139 80 83 49 89 27 47 130 92 133 87 51 112 76 49 109 49 57 93 73 22 117 50 64 58 97 139 36 131 111 133 58 33 8 88 55 38 90 46 30 118 57 29 82 74 41 117 38 46 94 92 5 105 15 117 70 103 68 60 120 48 21 110 85 40 81 38 58 129 56 10 99 86 76 81 26 23 25 68 16 28 127 65 18 71 75 77 100 26 11 130 104 28 34 56 106 7 8 120 112 12 58 21 130 124 67 61 19 87 119 ^ 286 1 35 94 61 130 98 35 88 34 65 104 56 126 118 50 87 10 81 109 90 86 118 32 6 114 88 39 38 39 62 3 12 134 72 137 35 75 81 115 106 140 112 11 123 41 103 45 95 84 71 107 13 26 110 96 62 16 109 84 59 53 38 27 8 28 13 32 137 17 138 41 122 36 99 65 99 83 36 112 29 49 70 96 126 136 131 116 3 18 17 126 142 14 37 141 141 123 42 13 20 83 42 139 83 54 49 58 42 7 137 29 48 16 121 127 34 52 140 106 128 58 36 124 83 24 69 54 61 112 17 6 95 97 24 57 86 124 59 71 119 67 1 109 54 68 49 57 132 32 5 71 113 40 80 104 75 106 133 31 126 130 104 62 9 39 44 66 116 141 135 96 132 19 41 121 126 124 77 8 4 60 82 6 101 124 89 51 123 48 40 85 77 21 112 10 69 66 115 87 16 108 30 84 65 80 103 32 131 134 73 47 10 63 39 50 93 37 135 114 69 48 34 58 23 27 133 37 9 40 98 41 115 99 70 83 29 42 67 133 55 79 80 91 122 12 2 115 112 23 33 16 102 3 19 60 101 130 105 116 117 27 2 1 103 38 14 55 78 26 116 123 54 67 139 82 74 70 84 72 17 132 25 68 31 120 103 140 ^ 285 1 65 30 51 119 48 107 92 84 69 28 136 143 54 20 6 70 47 142 64 4 65 59 73 99 134 146 102 125 116 57 137 137 72 48 128 78 5 80 63 54 85 30 22 129 68 21 21 74 28 128 107 27 60 2 93 95 71 37 11 37 15 39 102 3 104 65 80 59 52 113 34 20 67 60 27 81 135 46 106 106 102 68 128 17 15 100 124 15 43 136 122 100 67 142 35 14 53 120 2 89 93 99 73 9 122 39 77 15 96 90 43 79 134 60 92 105 55 96 31 119 77 97 72 23 140 38 30 43 83 136 88 107 117 72 109 118 58 91 119 73 95 100 59 138 123 54 49 143 50 133 66 106 45 80 88 42 93 5 59 77 101 74 110 104 40 92 19 77 76 86 102 129 3 144 101 139 134 56 90 18 91 94 85 55 10 137 11 58 1 107 113 70 22 7 56 29 143 111 8 46 45 116 122 129 89 7 121 53 95 14 49 118 62 125 91 37 97 15 35 100 63 140 63 50 51 58 26 127 6 45 59 102 121 114 85 141 135 10 72 19 106 66 66 41 53 13 38 1 21 103 50 108 46 66 70 43 140 124 40 63 144 97 137 47 60 88 103 115 132 145 116 143 115 10 133 9 118 37 105 51 94 60 67 117 116 ^ 305 1 109 110 75 42 12 139 137 43 128 106 107 19 126 12 101 148 127 15 117 125 125 62 96 13 76 70 96 101 110 138 8 95 76 143 17 32 97 79 149 39 31 94 123 21 41 135 55 84 70 33 135 118 50 62 121 81 1 45 144 93 60 5 64 137 8 105 91 82 67 27 113 119 53 18 98 79 48 84 32 135 128 5 1 20 76 17 85 108 72 36 141 140 49 150 105 104 3 149 14 54 18 148 64 49 125 37 28 28 101 22 104 91 32 82 117 12 114 69 58 2 58 115 9 108 47 59 65 14 92 7 4 86 98 16 82 92 95 38 94 10 10 48 97 104 66 115 97 142 115 122 119 40 97 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 40 122 84 108 22 142 140 99 44 15 54 8 42 125 150 130 21 79 124 62 46 119 15 29 91 57 150 42 138 71 61 68 80 114 6 1 70 121 18 35 113 56 87 86 10 73 14 29 41 72 89 1 133 87 101 123 59 90 142 77 133 52 78 48 34 138 134 27 17 60 131 147 61 93 148 39 132 49 62 71 36 91 4 139 49 100 120 43 113 144 30 94 73 127 40 34 50 100 110 88 114 94 35 138 33 72 61 58 65 24 107 6 54 81 114 56 137 71 11 23 19 73 1 108 110 25 148 11 98 132 150 17 70 146 50 ^ 314 1 99 88 7 139 24 13 35 47 97 145 74 36 119 3 51 84 48 119 53 49 15 79 17 120 103 148 64 30 41 97 120 75 111 63 58 131 134 18 13 10 48 18 16 48 43 15 54 18 41 47 122 144 80 92 145 77 1 33 89 54 46 78 48 21 54 43 40 53 24 16 73 42 94 29 44 34 151 152 23 123 12 142 140 43 37 88 29 19 35 72 96 151 130 62 112 34 36 91 120 50 112 138 2 105 60 68 137 131 5 17 19 139 74 11 120 78 149 58 128 15 104 16 126 78 20 57 134 71 49 90 76 108 126 100 54 68 39 132 153 42 147 146 124 62 87 35 75 61 65 46 100 82 105 113 31 63 5 95 54 71 77 127 150 80 36 144 2 130 59 74 39 3 152 121 122 18 117 12 117 141 118 135 62 36 69 5 39 53 150 52 153 143 30 66 96 126 131 56 137 8 7 86 142 14 7 111 141 93 136 137 134 43 12 89 23 44 9 152 146 121 97 19 38 110 91 67 14 32 110 66 68 8 130 84 73 118 59 24 41 72 121 150 55 37 138 27 104 66 124 9 51 109 47 125 109 148 8 29 47 72 146 149 61 93 10 20 54 15 76 133 125 106 110 94 32 9 29 148 36 66 121 125 56 112 9 1 111 116 94 57 8 108 50 62 140 71 74 89 1 83 152 20 85 17 145 102 39 56 115 47 150 108 64 98 ^ 335 1 28 103 19 92 95 152 152 10 11 13 155 67 11 83 101 69 153 152 45 141 14 120 129 140 119 59 2 89 73 70 83 29 16 67 81 29 1 54 65 96 117 2 37 47 128 33 3 89 108 98 139 49 78 27 103 39 119 94 132 90 38 132 55 65 131 90 58 2 54 100 69 118 22 44 19 7 148 93 25 29 123 81 64 131 55 30 1 89 38 97 82 64 9 28 86 123 151 10 133 40 154 102 4 111 65 9 63 59 124 116 72 105 76 57 137 97 32 145 108 78 112 50 43 34 75 20 22 129 68 11 118 74 125 118 57 17 20 129 53 65 61 144 1 17 142 156 52 100 54 15 20 59 52 63 131 20 57 124 31 125 46 106 76 92 8 98 154 152 80 114 15 140 136 112 100 17 92 25 151 150 80 99 69 83 49 43 156 102 19 57 122 96 30 3 39 134 40 32 75 5 76 127 138 99 17 57 52 150 130 18 127 33 23 116 107 78 77 77 42 69 68 48 41 69 33 75 40 49 128 103 4 146 93 10 83 66 96 152 30 38 12 33 5 39 47 41 34 60 74 20 42 156 67 46 56 102 89 3 124 81 99 104 56 50 8 61 74 55 15 87 108 28 138 47 93 60 2 124 46 126 103 91 145 36 25 116 122 79 79 7 111 13 85 121 9 98 32 125 81 134 77 112 15 70 33 110 13 50 148 8 133 127 153 45 19 42 121 94 45 91 95 117 22 9 46 6 26 31 53 150 8 148 128 53 141 ^ 326 0 80 123 24 147 1 112 82 159 63 74 97 109 33 151 32 89 87 132 117 46 129 59 115 91 114 118 37 21 9 94 60 25 89 47 79 110 55 12 143 99 87 43 88 56 57 160 76 12 71 128 77 146 117 95 105 42 66 3 76 20 76 101 100 118 149 45 26 143 148 32 57 39 129 19 31 84 123 1 152 135 5 54 30 13 125 68 30 62 101 51 142 5 94 83 20 116 24 107 109 105 91 42 17 27 93 69 3 139 68 79 38 84 2 85 128 126 122 131 46 17 35 98 42 26 111 100 29 120 55 84 114 109 145 14 18 138 14 9 85 7 18 129 91 2 94 51 133 82 87 123 64 39 8 103 38 75 110 78 7 9 45 115 42 138 135 86 78 16 62 52 75 159 54 151 121 149 77 74 16 85 47 102 105 82 119 10 67 137 153 148 135 28 49 26 151 153 36 80 11 130 113 24 44 30 102 24 58 133 122 140 99 24 156 54 119 42 115 140 90 132 19 94 2 157 99 136 19 71 7 130 153 108 51 21 58 70 74 137 1 40 111 149 5 103 6 27 76 141 23 125 140 1 72 29 152 103 87 51 93 29 80 132 77 123 153 68 159 14 98 114 158 121 158 81 137 41 93 118 140 122 19 22 31 147 41 4 89 150 50 120 144 113 104 20 44 53 97 20 4 90 60 48 84 74 25 138 23 62 61 159 5 14 107 6 4 81 114 46 97 11 112 154 130 73 132 60 ^ 325 0 58 137 96 11 98 67 98 103 57 146 21 59 88 151 139 148 127 25 17 47 115 34 160 109 107 51 64 28 69 13 49 149 69 141 90 93 118 64 10 1 67 80 35 111 13 58 101 124 132 147 154 18 162 6 162 33 5 34 142 41 161 82 114 70 92 145 57 155 137 114 79 44 36 48 48 21 14 13 40 33 14 150 33 32 54 143 14 4 101 142 23 93 136 132 120 147 17 38 163 143 5 52 46 151 130 32 72 34 124 150 51 100 112 128 126 65 10 28 87 81 159 131 19 99 54 125 110 58 119 28 78 129 104 140 126 38 154 27 114 61 153 90 66 98 76 50 158 48 39 82 123 22 147 136 114 52 37 35 75 41 15 150 60 52 55 103 21 23 129 95 24 71 47 97 130 50 140 144 106 100 9 64 19 117 122 71 92 8 77 156 97 121 98 85 2 36 39 109 143 23 120 156 133 93 154 36 66 116 131 160 127 162 161 46 142 14 141 81 141 63 86 117 104 3 146 39 127 34 133 102 106 91 57 9 28 60 61 7 158 12 80 26 8 122 80 44 63 68 49 158 21 32 81 150 15 141 108 161 64 46 124 123 31 99 27 105 109 98 112 9 37 12 116 149 51 73 144 124 4 119 46 133 75 86 90 84 2 9 19 108 6 16 101 115 16 92 163 125 101 106 64 37 8 68 40 42 130 41 24 89 115 43 112 85 121 125 92 154 9 46 115 7 140 108 158 ^ 336 0 38 42 155 103 9 62 65 102 122 10 138 160 125 47 158 43 91 69 123 132 35 121 4 110 89 130 69 29 139 69 53 70 83 29 163 67 41 9 108 34 45 76 87 2 144 164 98 33 160 79 78 48 89 9 38 134 93 146 79 54 122 80 38 112 55 55 101 70 8 129 44 70 59 98 149 24 136 124 138 63 25 166 83 51 34 91 45 30 118 59 28 87 72 44 116 28 36 103 101 113 10 114 62 111 71 65 126 53 19 114 86 42 85 36 57 137 57 159 95 88 78 72 20 23 14 65 10 22 129 68 1 68 74 75 108 7 7 147 109 13 35 51 104 158 164 122 126 2 50 4 132 127 59 52 13 81 20 47 107 74 148 115 46 106 46 82 115 68 144 142 60 104 15 90 136 102 100 134 42 15 141 100 40 49 49 73 166 13 156 82 166 37 82 96 137 130 166 134 20 139 45 122 56 107 98 79 124 17 32 130 120 165 77 23 130 96 67 68 47 37 12 29 18 38 158 19 160 55 147 39 118 83 121 96 43 137 33 66 86 112 147 155 149 140 5 19 17 148 161 10 44 159 146 57 16 26 102 49 3 104 61 59 74 56 10 165 31 54 25 142 157 37 58 165 128 154 73 50 149 94 36 76 63 71 135 26 5 116 122 29 69 7 101 140 75 81 136 78 2 125 71 84 57 62 162 40 3 80 130 50 98 125 93 127 153 45 146 149 121 74 5 41 55 77 139 166 153 113 153 21 53 140 145 148 88 162 ^ 341 0 4 62 78 167 102 144 94 55 141 63 29 97 91 24 115 166 80 69 132 99 1 120 23 88 64 87 118 37 137 152 94 60 168 71 47 52 110 37 155 125 63 42 43 52 11 12 151 31 12 44 110 32 128 117 68 87 24 39 164 76 145 58 101 91 100 140 151 143 130 32 21 3 111 1 31 75 123 153 116 135 130 27 164 165 116 23 12 62 83 24 133 139 49 74 154 80 158 80 64 105 91 6 142 27 75 24 128 112 41 79 29 84 145 40 128 99 95 95 19 17 160 89 15 17 84 64 11 93 10 66 78 73 127 148 18 129 139 143 49 150 9 84 82 154 85 15 88 82 60 87 19 12 133 58 20 39 65 51 141 134 27 70 167 120 117 86 60 16 44 16 57 132 18 142 85 104 59 47 141 58 2 66 96 46 119 153 40 110 126 103 90 144 13 26 106 144 80 145 134 103 95 24 44 21 84 140 13 97 104 140 99 6 147 54 83 42 106 131 54 96 135 67 118 121 81 109 10 53 132 112 117 81 33 155 49 61 38 119 1 13 102 131 148 94 131 143 67 123 148 89 104 135 72 145 152 76 87 6 66 2 71 123 77 114 108 59 123 166 62 96 140 94 149 116 36 128 23 93 91 95 113 162 156 165 111 166 4 44 105 5 120 99 113 68 11 169 35 70 2 147 125 81 15 12 57 56 16 138 14 53 61 114 121 5 107 6 129 81 114 37 61 127 67 136 94 73 114 32 34 119 72 11 98 37 74 73 51 146 161 35 146 ^ 349 0 142 139 121 91 16 163 2 88 171 133 100 62 51 46 10 24 150 49 131 60 114 63 84 91 64 165 138 40 44 172 111 141 58 74 115 96 129 145 164 153 170 126 24 169 16 115 41 125 46 87 61 92 145 39 155 92 78 70 35 27 21 48 21 151 159 40 15 5 132 170 23 18 107 160 150 56 133 23 66 109 123 102 102 172 166 145 116 151 34 1 151 130 5 36 34 97 114 15 82 128 112 119 99 29 138 165 42 36 159 95 19 63 36 89 101 40 92 1 33 93 104 113 126 2 136 96 52 108 90 57 89 31 5 113 30 39 37 96 4 147 127 105 43 165 35 75 23 143 105 24 25 10 94 12 160 102 95 170 71 20 70 112 23 95 144 61 73 137 55 1 81 95 26 65 172 41 147 79 103 80 40 121 36 12 64 98 169 93 111 115 48 127 9 39 107 131 115 118 162 161 10 142 14 123 54 141 36 41 99 77 140 128 167 82 25 106 57 70 64 21 19 15 34 126 149 167 53 163 127 86 35 8 54 23 40 140 3 169 45 150 152 96 81 143 28 28 124 87 13 90 9 87 109 53 67 164 28 131 89 149 42 55 126 79 132 74 19 133 30 68 72 75 148 9 10 72 152 144 83 106 153 74 163 98 92 97 37 19 8 32 31 24 121 14 152 89 79 7 76 155 85 76 107 83 154 155 37 115 144 131 108 116 26 36 137 103 3 44 47 72 104 10 120 154 107 35 152 19 85 69 105 120 29 109 171 104 65 124 39 11 127 57 41 70 83 29 157 67 164 ^ 370 1 167 63 16 27 58 60 2 99 128 71 33 160 70 51 3 44 149 2 89 84 101 43 18 113 71 38 94 55 46 74 52 139 102 35 43 50 80 122 6 100 88 129 36 25 148 47 24 7 55 36 30 82 32 19 78 63 26 71 28 167 85 56 167 95 159 78 26 66 35 65 90 44 159 105 59 15 67 57 137 21 132 50 70 78 36 169 5 172 56 1 22 129 68 168 23 74 30 99 138 174 120 91 153 8 42 68 158 155 104 99 133 5 135 96 82 59 52 144 36 20 38 62 29 112 106 46 106 19 73 70 41 135 133 42 95 15 45 136 93 100 98 173 6 132 55 4 4 31 64 130 162 156 64 157 19 46 96 92 103 139 134 2 94 18 86 38 89 62 61 79 157 14 112 111 156 32 14 85 78 31 59 20 1 161 169 149 29 122 150 133 37 102 30 109 65 85 51 174 110 164 66 77 76 111 119 131 95 5 1 166 103 134 141 17 158 123 137 48 165 175 102 13 3 86 43 23 47 56 150 165 4 36 174 115 157 168 13 147 119 109 55 41 140 67 27 31 27 53 126 17 163 116 122 160 60 7 92 113 66 45 109 60 151 125 62 39 39 17 153 13 152 53 94 50 53 89 57 127 153 45 119 104 121 56 145 172 19 41 103 166 108 68 126 12 53 131 127 148 52 134 168 50 48 155 72 132 82 37 129 63 175 97 79 18 91 148 74 57 132 87 147 114 175 70 46 69 118 37 107 140 94 60 156 59 47 34 110 25 143 113 39 12 43 28 157 158 145 1 12 26 98 2 116 117 50 75 12 21 164 76 121 46 101 85 88 134 146 127 143 79 ^ 364 0 32 164 146 93 162 31 66 123 144 80 135 94 137 156 107 157 173 62 65 176 124 112 4 65 127 44 131 53 19 105 91 149 106 27 57 158 92 85 14 79 20 84 127 174 128 72 68 59 171 17 124 80 167 8 57 28 172 66 144 48 42 37 109 121 18 120 103 116 13 132 39 73 145 76 158 43 82 33 51 153 164 97 13 2 3 20 24 114 98 9 25 131 102 99 86 42 16 26 159 39 105 161 133 49 59 41 20 105 31 136 30 87 10 119 135 13 83 99 58 45 99 156 26 61 135 143 80 118 107 76 77 24 44 12 66 95 147 61 86 140 99 167 138 54 47 42 97 122 18 60 90 40 73 85 63 82 1 35 96 94 81 54 15 128 40 52 2 101 1 165 93 113 130 85 95 98 58 105 112 53 68 108 72 100 152 49 87 140 39 154 62 114 77 105 63 50 87 157 26 78 122 67 140 71 170 119 5 93 64 50 104 144 129 138 75 130 4 178 60 139 120 54 113 32 2 133 17 43 163 129 89 72 149 155 30 38 7 138 5 44 61 69 76 175 107 6 93 81 114 28 25 82 22 118 58 73 96 175 177 92 36 11 98 171 38 28 42 146 125 178 88 136 139 103 67 10 151 151 70 153 115 94 32 51 34 177 173 132 49 119 54 96 45 78 73 64 159 120 22 20 154 111 117 58 56 109 72 117 139 152 147 170 102 18 169 4 97 41 101 22 69 55 92 145 27 155 62 54 64 29 21 3 48 21 133 147 40 3 178 120 152 17 173 83 148 138 26 127 23 48 91 117 90 72 166 142 133 98 139 22 150 151 130 140 ^ 372 0 34 70 78 161 64 92 112 110 72 175 102 138 179 173 159 59 19 27 18 53 92 22 65 156 170 57 104 86 126 148 118 155 78 43 63 90 48 80 168 142 68 12 39 174 69 168 147 118 96 34 129 35 75 5 107 60 170 180 147 85 3 133 75 95 152 71 175 43 94 178 50 144 16 46 101 46 165 45 68 163 38 172 5 138 61 85 62 177 76 36 167 19 53 151 66 66 97 3 100 164 12 98 131 70 109 162 161 156 142 14 105 27 141 9 178 81 50 113 110 131 37 16 79 12 34 37 167 173 10 152 7 81 140 158 26 136 82 50 172 154 45 160 31 122 167 142 9 150 125 51 54 125 174 10 124 51 177 81 173 69 109 8 22 155 19 86 62 149 33 37 108 34 96 29 174 133 167 50 54 66 130 9 1 36 134 108 65 97 126 56 163 71 83 88 10 1 8 178 22 6 112 169 116 89 43 153 40 146 85 31 89 74 154 137 28 115 117 122 108 98 8 27 110 103 176 17 20 27 77 10 93 145 80 17 143 165 76 69 78 102 20 91 171 95 29 115 176 166 109 39 23 70 83 29 148 67 163 161 33 4 15 46 42 2 69 104 53 33 160 64 33 155 14 131 160 59 78 71 19 176 107 65 38 82 55 40 56 40 115 84 29 25 44 68 104 176 76 64 123 18 25 136 23 6 171 31 30 30 58 14 13 72 57 14 41 28 143 73 26 167 83 147 54 2 36 11 65 66 38 141 99 41 179 55 158 57 137 179 114 20 58 78 12 157 175 166 50 177 22 129 68 168 175 74 93 114 174 102 79 135 172 36 44 158 149 92 81 109 157 111 72 119 ^ 372 0 59 52 112 180 20 30 22 173 80 98 46 106 179 65 30 17 127 125 26 87 15 5 136 85 100 66 141 182 124 15 156 148 15 56 98 146 156 48 149 3 14 96 52 79 115 134 170 54 178 54 22 73 30 45 39 133 182 96 103 148 176 6 45 62 183 51 180 153 145 145 117 21 90 118 109 21 62 22 101 49 53 11 142 86 132 66 69 44 79 87 115 55 5 169 150 63 110 109 177 150 91 129 40 149 159 102 165 3 70 27 175 23 56 126 165 164 20 158 91 157 136 157 131 111 69 39 33 132 43 19 175 179 37 118 9 155 116 122 128 52 7 84 89 58 13 85 44 135 125 54 183 23 161 145 173 136 29 62 50 13 57 25 127 153 45 95 64 121 40 121 140 171 9 71 166 68 28 102 4 53 123 111 148 20 102 160 34 8 139 32 116 66 13 113 63 143 97 63 10 59 124 66 41 132 71 115 106 151 46 22 45 118 37 67 124 94 60 140 43 47 10 110 9 127 97 7 156 43 180 125 126 137 145 12 2 82 146 100 117 26 59 180 181 164 76 89 30 101 77 72 126 114 95 143 102 32 149 131 83 157 31 61 123 139 60 135 74 169 122 151 102 137 168 62 55 166 119 97 163 60 112 24 116 38 178 105 91 134 86 27 47 138 72 70 183 79 15 84 117 154 128 57 53 39 161 17 104 75 157 3 42 8 167 51 124 38 22 17 99 106 18 115 83 101 177 122 179 14 68 140 71 143 18 82 18 31 133 154 77 172 176 167 179 9 99 78 183 111 92 89 86 32 16 16 144 29 90 146 128 29 34 31 5 85 16 116 10 82 174 119 125 79 ^ 391 0 59 75 18 5 59 132 26 21 127 119 80 94 83 52 61 24 44 4 50 55 115 29 70 140 99 159 130 54 15 42 89 114 173 28 50 16 33 53 47 58 180 19 64 78 49 30 186 104 32 44 157 85 1 149 85 97 114 77 63 58 50 89 80 21 36 84 72 60 152 25 87 108 15 138 54 106 77 97 23 42 55 149 181 62 106 43 132 31 138 111 176 93 40 10 96 128 105 114 43 98 4 146 20 107 120 14 113 181 101 1 19 155 113 57 64 117 131 6 22 186 138 184 36 61 29 36 175 107 6 61 81 114 20 180 42 169 102 26 73 80 151 153 68 4 11 98 139 6 175 34 146 93 154 88 128 139 79 35 2 135 119 46 129 91 86 179 51 18 169 141 108 49 103 46 72 21 70 49 64 151 96 185 175 130 111 85 58 32 101 40 101 131 136 139 170 70 10 169 175 73 41 69 177 45 47 92 145 11 155 22 22 56 21 13 166 48 21 109 131 40 174 178 104 128 9 149 51 132 122 173 119 23 24 67 109 74 32 158 110 117 74 123 6 118 151 130 150 167 34 55 58 146 54 72 112 105 57 160 82 123 159 153 159 39 19 7 8 33 87 12 50 146 150 37 104 71 126 133 108 145 68 38 38 90 43 75 148 122 43 2 39 154 54 163 147 113 91 29 109 35 75 182 87 35 155 170 127 80 185 118 60 95 142 71 165 28 84 168 25 144 178 31 81 41 160 25 53 143 23 172 172 133 51 75 52 157 51 36 157 181 28 141 51 41 87 165 85 154 184 93 131 45 104 162 161 141 142 14 95 12 141 181 158 71 35 98 100 111 12 11 64 174 14 22 152 173 5 132 179 56 135 153 11 121 57 30 152 139 40 140 53 ^ 384 1 106 159 118 167 150 101 11 30 109 150 184 124 19 169 73 165 53 109 158 172 147 11 46 38 149 25 21 92 184 64 179 158 133 135 34 38 58 114 9 183 4 118 76 49 89 102 40 163 47 75 80 176 175 8 154 14 180 104 153 84 89 11 129 8 138 85 181 73 66 154 121 20 115 93 114 108 82 182 19 86 103 176 183 186 177 53 10 69 137 56 1 135 141 68 69 54 86 12 75 171 87 187 107 144 150 93 23 7 70 83 29 140 67 139 153 183 178 189 30 18 2 29 72 29 33 160 56 9 123 164 107 136 19 70 31 177 152 99 57 38 66 55 32 32 24 83 60 21 1 36 52 80 168 44 32 115 184 25 120 181 172 155 189 22 30 26 180 5 64 49 188 1 28 111 57 176 167 67 131 22 160 186 169 65 34 30 117 91 17 163 39 134 57 137 155 90 170 42 78 170 141 167 158 42 177 22 129 68 168 143 74 150 85 82 174 78 63 111 156 28 12 158 141 76 57 77 125 79 40 12 59 52 88 156 20 24 182 149 56 92 46 106 167 59 189 121 119 14 81 15 165 136 79 100 42 117 182 118 175 138 124 3 50 74 134 156 36 143 181 180 96 22 61 97 134 164 24 166 30 10 61 6 33 9 115 176 84 97 142 152 15 50 165 45 168 135 133 127 93 15 66 94 91 9 32 16 95 37 29 171 118 68 108 66 63 20 55 63 103 25 5 163 138 33 92 85 165 144 67 123 34 137 147 102 147 3 58 15 157 5 56 108 165 152 8 146 73 157 112 133 119 105 39 27 27 126 25 13 151 161 25 112 3 149 116 122 104 46 7 78 71 52 179 67 32 123 125 48 159 11 137 139 161 110 ^ 394 0 2 26 50 161 21 182 127 153 45 68 19 121 22 94 104 144 166 35 166 23 176 75 188 53 114 93 148 177 66 151 16 156 121 180 98 48 179 95 63 107 97 45 1 23 97 57 23 132 53 79 97 124 19 188 18 118 37 22 106 94 60 122 25 47 176 110 184 109 79 164 120 43 153 89 90 128 109 12 168 64 110 82 117 192 41 171 163 164 76 53 12 101 68 54 117 78 59 143 84 32 122 104 65 148 31 52 123 130 24 135 38 151 95 142 93 101 159 62 37 148 110 70 127 51 85 181 89 11 142 105 91 107 50 27 29 102 36 43 165 79 6 84 99 118 128 30 26 3 143 17 68 66 139 187 15 165 158 24 88 20 179 174 81 79 18 106 47 74 150 104 179 162 59 131 62 116 166 82 184 188 97 136 41 136 167 140 143 175 72 42 174 148 75 74 71 86 14 16 191 117 11 63 119 119 186 182 13 171 49 182 80 167 73 147 119 107 164 41 57 181 168 29 114 26 184 121 101 80 76 65 34 49 24 44 191 38 25 91 5 58 140 99 153 124 54 184 42 83 108 155 4 20 191 3 29 35 40 180 7 40 66 25 12 180 86 26 38 139 73 1 137 79 85 102 71 39 28 44 77 56 190 12 66 72 30 152 7 87 84 190 126 48 100 77 91 186 36 31 143 163 50 94 25 126 1 114 105 170 93 22 173 90 116 87 96 19 74 4 122 183 83 120 177 113 169 181 77 182 1 149 101 33 58 93 113 181 10 186 138 184 30 61 192 6 175 107 6 37 81 114 14 162 12 145 90 2 73 68 133 135 50 173 11 98 115 175 151 28 146 69 136 88 122 139 61 11 189 123 95 28 111 73 80 155 51 6 163 117 90 49 91 40 54 189 ^ 390 0 62 25 64 143 72 169 151 106 111 53 58 8 93 8 85 123 120 131 170 38 2 169 167 49 41 37 153 21 39 92 145 190 155 177 185 48 13 5 150 48 21 85 115 40 166 178 88 104 1 125 19 116 106 141 111 23 43 101 58 187 150 78 101 50 107 185 86 151 130 134 143 34 31 26 122 38 40 112 97 33 136 50 99 127 121 159 7 19 170 187 1 79 191 26 130 118 5 104 47 126 109 92 129 52 30 193 90 35 67 116 90 3 181 39 122 30 155 147 105 83 21 77 35 75 174 55 190 131 154 95 72 185 94 36 95 126 71 149 4 68 152 180 144 146 7 49 33 152 188 29 111 194 172 148 125 35 59 36 125 11 36 141 149 183 125 27 1 71 133 61 138 168 85 131 5 96 162 161 117 142 14 79 183 141 165 126 55 11 74 84 79 167 3 40 142 177 193 128 173 192 100 163 16 127 145 182 97 17 193 120 115 32 108 18 96 154 103 152 150 86 181 15 99 135 179 124 194 164 68 160 43 109 138 152 142 6 21 23 149 20 11 82 164 44 159 148 133 115 24 28 53 104 9 183 179 108 56 39 84 87 30 163 32 70 75 166 170 8 139 9 175 99 143 64 89 186 114 183 133 85 161 63 61 154 111 15 115 78 109 108 72 177 14 71 103 176 173 176 157 38 10 54 132 41 186 130 126 63 69 39 76 7 65 171 82 172 102 124 140 83 13 192 70 83 29 135 67 124 148 163 173 184 20 3 2 4 52 14 33 160 51 189 103 144 92 121 189 65 6 162 137 94 52 38 56 55 27 17 14 63 45 16 181 31 42 65 163 24 12 110 174 25 110 166 162 145 174 17 30 6 170 59 44 183 171 28 91 47 156 172 ^ 400 1 51 115 188 136 154 145 65 2 22 93 83 191 147 23 110 57 137 131 66 138 26 78 146 125 159 150 34 177 22 129 68 168 111 74 118 77 50 174 54 47 87 140 20 178 158 133 60 33 45 93 47 8 170 59 52 56 124 20 16 150 117 24 84 46 106 151 51 158 173 113 111 196 73 15 133 136 71 100 10 85 182 110 143 114 92 185 42 42 118 156 20 135 173 156 96 180 37 73 134 156 182 150 196 192 45 172 17 167 91 168 68 89 134 120 190 173 34 141 37 152 111 117 103 61 7 34 62 67 191 190 8 87 21 195 139 86 44 76 66 55 186 23 31 87 183 5 155 122 191 68 53 149 136 35 115 26 121 131 102 123 3 42 197 133 179 56 84 165 136 190 130 49 157 80 101 103 97 197 11 19 118 1 5 119 137 9 104 193 141 116 122 72 38 7 70 47 44 155 43 16 107 125 40 127 193 105 131 145 108 185 6 50 141 1 167 127 153 45 53 192 121 12 79 84 129 151 15 166 196 156 60 188 53 109 83 148 162 46 146 6 136 111 160 88 38 169 85 63 87 97 35 194 3 82 52 13 132 43 59 92 109 4 178 3 118 37 195 96 94 60 112 15 47 166 110 179 99 69 149 100 43 138 69 70 123 89 12 158 54 90 72 117 182 31 166 153 164 76 33 2 101 63 44 112 58 39 143 74 32 107 89 55 143 31 47 123 125 4 135 18 141 80 137 88 81 154 62 27 138 105 55 107 46 70 166 74 194 122 105 91 92 30 27 19 82 16 28 155 79 1 84 89 98 128 15 11 181 133 17 48 61 129 187 150 153 9 68 10 164 159 71 64 18 101 27 59 135 94 179 142 54 126 57 101 146 82 174 173 77 126 21 116 162 125 123 165 57 22 169 153 ^ 394 0 47 60 57 86 16 184 96 197 42 98 112 165 154 199 157 21 168 52 146 66 126 119 93 150 20 36 153 140 194 93 26 156 114 80 80 55 44 13 35 24 44 191 24 190 63 177 44 140 99 146 117 54 163 42 76 101 134 176 185 177 168 1 21 19 180 193 12 52 197 191 173 65 19 31 118 59 1 123 72 71 88 64 11 193 37 63 28 169 184 45 72 195 152 186 87 56 176 112 41 93 77 84 158 29 3 136 142 36 80 4 119 166 86 98 163 93 1 145 83 102 66 75 191 46 4 94 155 55 120 149 113 148 181 49 175 180 142 87 5 51 65 92 167 196 186 138 184 23 61 164 171 175 107 6 9 81 114 7 141 177 117 76 174 73 54 112 114 29 152 11 98 87 154 123 21 146 41 115 88 115 139 40 183 189 109 67 7 90 52 73 127 51 192 156 89 69 49 77 33 33 182 57 10 64 138 57 159 136 91 111 33 58 193 88 188 75 118 110 126 170 18 197 169 162 34 41 17 138 6 34 92 145 185 155 157 170 43 8 140 48 21 70 105 40 161 178 78 89 196 110 199 106 96 121 106 23 185 28 96 48 167 145 58 91 35 97 180 66 151 130 124 128 34 16 6 107 28 20 112 92 18 121 30 84 107 101 159 187 19 155 182 181 74 186 11 120 98 185 104 32 126 94 82 119 42 25 173 90 30 62 96 70 178 176 39 102 15 150 147 100 78 16 57 35 75 169 35 170 116 144 75 67 185 79 21 95 116 71 139 189 58 142 160 144 126 192 29 28 147 173 14 91 184 172 133 120 25 49 26 105 186 36 131 129 163 115 12 176 61 113 46 128 158 80 131 180 91 162 161 102 142 14 69 173 141 155 106 45 196 59 74 59 147 195 ^ 412 0 16 110 153 177 104 173 192 68 147 179 119 137 166 73 180 169 88 91 24 76 10 80 146 79 128 150 62 149 194 83 111 171 124 170 156 60 152 27 109 106 120 134 201 184 202 149 12 198 66 132 12 127 132 133 83 8 12 45 88 9 183 155 92 24 23 76 63 14 163 8 62 67 150 162 8 115 1 167 91 127 32 89 162 90 159 125 85 129 47 53 154 95 7 115 54 101 108 56 169 6 47 103 176 157 160 125 14 10 30 124 17 178 122 102 55 69 15 60 202 49 171 74 148 94 92 124 67 200 184 70 83 29 127 67 100 140 131 165 176 4 182 2 167 20 193 33 160 43 173 71 112 68 97 157 57 169 138 113 86 44 38 40 55 19 196 201 31 21 8 165 23 26 41 155 195 183 102 158 25 94 142 146 129 150 9 30 177 154 195 51 36 175 139 28 59 31 124 167 41 105 173 121 134 130 65 185 17 78 78 181 137 13 95 57 137 116 51 118 16 78 131 115 154 145 29 177 22 129 68 168 91 74 98 72 30 174 39 37 72 130 15 163 158 128 50 18 25 73 27 191 150 59 52 36 104 20 11 130 97 4 79 46 106 141 46 138 163 108 106 191 68 15 113 136 66 100 193 65 182 105 123 99 72 180 37 22 108 156 10 130 168 141 96 160 22 58 134 151 162 140 181 187 35 157 7 147 76 163 58 84 129 100 190 153 24 126 32 142 96 107 88 41 2 14 42 52 186 170 3 82 11 180 119 66 29 56 66 50 171 3 11 77 163 5 150 112 171 53 33 139 131 15 110 21 111 121 102 108 3 32 192 118 169 56 69 165 126 185 120 34 157 60 81 93 92 177 1 14 113 189 99 122 202 99 193 136 116 122 52 33 7 65 32 39 140 28 6 97 125 35 107 188 85 126 135 98 175 189 50 121 184 116 ^ 413 1 127 153 45 32 164 121 203 58 56 108 130 192 166 168 128 39 188 53 102 69 148 141 18 139 197 108 97 132 74 24 155 71 63 59 97 21 194 180 61 45 204 132 29 31 85 88 188 164 187 118 37 167 82 94 60 98 1 47 152 110 172 85 55 128 72 43 117 41 42 116 61 12 144 40 62 58 117 168 17 159 139 164 76 5 193 101 56 30 105 30 11 143 60 32 86 68 41 136 31 40 123 118 181 135 195 127 59 130 81 53 147 62 13 124 98 34 79 39 49 145 53 180 94 105 91 71 2 27 5 54 193 7 141 79 199 84 75 70 128 199 195 160 119 17 20 54 115 187 184 129 146 193 40 201 143 138 57 43 18 94 204 38 114 80 179 114 47 119 50 80 118 82 160 152 49 112 198 88 155 104 95 151 36 199 162 100 27 50 47 86 195 16 179 81 192 27 83 107 150 134 194 147 1 158 32 131 61 111 119 83 140 5 21 133 120 174 78 26 136 109 65 80 40 29 203 25 24 44 191 14 170 43 162 34 140 99 141 112 54 148 42 71 96 119 161 165 167 148 186 11 4 180 188 197 42 182 181 168 50 14 26 103 49 1 113 67 61 78 59 196 173 32 53 8 154 169 30 72 175 152 176 87 36 166 102 36 88 77 79 138 24 188 131 127 26 70 194 114 146 66 93 158 93 191 125 78 92 51 60 176 26 4 74 135 35 120 129 113 133 181 29 170 170 137 77 190 46 45 77 157 191 186 138 184 18 61 144 151 175 107 6 194 81 114 2 126 157 97 66 159 73 44 97 99 14 137 11 98 67 139 103 16 146 21 100 88 110 139 25 168 189 99 47 197 75 37 68 107 51 187 151 69 54 49 67 28 18 172 52 200 64 133 42 149 121 76 111 13 58 183 83 173 65 113 100 121 170 203 197 169 157 19 202 ^ 434 1 193 114 190 26 92 145 177 155 125 146 35 200 124 48 21 46 89 40 153 178 62 65 196 86 175 90 80 89 98 23 169 4 88 32 135 137 26 75 11 81 172 34 151 130 108 104 34 200 182 83 12 196 112 84 202 97 206 60 75 69 159 163 19 131 174 157 66 178 195 104 66 161 104 8 126 70 66 103 26 17 141 90 22 54 64 38 146 168 39 70 199 142 147 92 70 8 25 35 75 161 3 138 92 128 43 59 185 55 205 95 100 71 123 173 42 126 128 144 94 176 205 20 139 149 198 59 168 172 109 112 9 33 10 73 154 36 115 97 131 99 196 144 45 81 22 112 142 72 131 148 83 162 161 78 142 14 53 157 141 139 74 29 180 35 58 27 115 198 1 90 138 167 89 173 192 48 137 159 114 132 156 58 160 154 68 76 19 56 5 70 141 64 113 150 47 129 184 73 96 166 124 155 151 55 147 17 109 86 100 129 201 164 192 149 7 193 56 112 200 107 122 133 63 206 2 40 78 9 183 140 82 4 13 71 48 4 163 201 57 62 140 157 8 100 204 162 86 117 12 89 147 75 144 120 85 109 37 48 154 85 2 115 39 96 108 46 164 1 32 103 176 147 150 105 207 10 15 119 2 173 117 87 50 69 50 202 39 171 69 133 89 72 114 57 195 179 70 83 29 122 67 85 135 111 160 171 202 172 2 147 183 33 160 38 163 51 92 53 82 137 52 149 123 98 81 39 38 30 55 14 186 196 11 6 3 155 18 16 26 150 180 168 97 148 25 84 127 136 119 135 4 30 162 144 195 46 31 170 119 28 39 21 104 167 31 95 158 106 114 115 65 170 12 63 73 171 127 3 80 57 137 101 36 98 6 78 116 105 149 140 24 177 22 129 68 168 71 74 78 67 10 174 24 27 57 120 10 148 158 123 40 3 5 53 7 176 130 59 52 16 84 20 6 110 77 192 74 46 106 131 41 118 153 144 ^ 438 1 99 184 61 15 85 136 59 100 172 37 182 98 95 78 44 173 30 204 94 156 206 123 161 120 96 132 1 37 134 144 134 126 160 180 21 136 203 119 55 156 44 77 122 72 190 125 10 105 25 128 75 93 67 13 205 196 14 31 179 142 206 75 207 159 91 38 8 28 66 43 150 185 193 63 135 5 143 98 143 32 5 125 124 197 103 14 97 107 102 87 3 18 185 97 155 56 48 165 112 178 106 13 157 32 53 79 85 149 197 7 106 175 203 71 101 195 92 193 129 116 122 24 26 7 58 11 32 119 7 202 83 125 28 79 181 57 119 121 84 161 168 50 93 163 131 127 153 45 17 144 121 198 43 36 93 115 177 166 148 108 24 188 53 97 59 148 126 208 134 192 88 87 112 64 14 145 61 63 39 97 11 194 165 46 40 199 132 19 11 80 73 178 154 177 118 37 147 72 94 60 88 201 47 142 110 167 75 45 113 52 43 102 21 22 111 41 12 134 30 42 48 117 158 7 154 129 164 76 195 188 101 51 20 100 10 201 143 50 32 71 53 31 131 31 35 123 113 166 135 180 117 44 125 76 33 142 62 3 114 93 19 59 34 34 130 38 170 74 105 91 56 192 27 205 34 178 202 131 79 199 84 65 50 128 189 185 145 109 17 49 105 187 174 114 141 183 20 196 128 123 47 28 18 89 189 23 99 70 179 94 42 114 45 65 98 82 150 137 29 102 183 68 150 89 75 141 21 184 157 80 7 40 37 86 190 16 174 66 187 12 68 102 135 114 189 137 191 148 12 116 56 96 119 73 130 200 6 113 100 154 63 26 116 104 50 80 25 14 193 15 24 44 191 4 150 23 147 24 140 99 136 107 54 133 42 66 91 104 146 145 157 128 171 1 199 180 183 182 32 167 171 163 35 9 21 88 39 1 103 62 51 68 54 181 153 27 43 198 139 154 15 72 155 152 166 87 16 156 92 31 83 77 74 118 19 173 126 202 ^ 431 0 10 54 178 106 114 34 85 150 93 175 93 70 76 27 36 152 207 4 42 103 3 120 97 113 109 181 210 162 154 129 61 166 38 13 53 141 183 186 138 184 10 61 112 119 175 107 6 170 81 114 207 102 125 65 50 135 73 28 73 75 203 113 11 98 35 115 71 8 146 202 76 88 102 139 1 144 189 83 15 181 51 13 60 75 51 179 143 37 30 49 51 20 207 156 44 184 64 125 18 133 97 52 111 194 58 167 75 149 49 105 84 113 170 179 197 169 149 208 41 178 99 180 21 92 145 172 155 105 131 30 208 200 114 48 21 31 79 40 148 178 52 50 196 71 160 80 70 69 93 23 159 202 83 22 115 132 6 65 209 71 167 14 151 130 98 89 34 190 167 68 2 181 112 79 192 82 191 45 55 49 159 148 19 116 169 142 61 173 185 94 46 146 104 206 126 55 56 93 16 12 121 90 17 49 44 18 126 163 39 50 189 137 147 87 65 3 5 35 75 156 196 118 77 118 23 54 185 40 195 95 90 71 113 163 32 116 108 144 74 166 190 15 134 134 188 39 158 172 94 107 212 23 53 134 36 105 77 111 89 186 124 35 61 7 102 132 67 131 128 78 162 161 63 142 14 43 147 141 129 54 19 170 20 48 7 95 198 199 70 123 157 74 173 192 28 127 139 109 127 146 43 140 139 48 61 14 36 60 136 49 98 150 32 109 174 63 81 161 124 140 146 50 142 7 109 66 80 124 201 144 182 149 2 188 46 92 185 87 112 133 43 201 205 35 68 9 183 125 72 197 3 66 33 207 163 191 52 57 130 152 8 85 204 157 81 107 205 89 132 60 129 115 85 89 27 43 154 75 210 115 24 91 108 36 159 209 17 103 176 137 140 85 197 10 114 200 168 112 72 45 69 198 40 202 29 171 64 118 84 52 104 47 190 174 70 83 29 117 67 70 130 91 155 166 197 162 2 127 193 173 82 ^ 464 1 160 31 149 23 64 32 61 109 45 121 102 77 74 32 38 16 55 7 172 189 198 200 211 141 11 2 5 143 159 147 90 134 25 70 106 122 105 114 212 30 141 130 195 39 24 163 91 28 11 7 76 167 17 81 137 85 86 94 65 149 5 42 66 157 113 204 59 57 137 80 15 70 207 78 95 91 142 133 17 177 22 129 68 168 43 74 50 60 197 174 3 13 36 106 3 127 158 116 26 197 192 25 194 155 102 59 52 203 56 20 214 82 49 171 67 46 106 117 34 90 139 96 94 179 56 15 65 136 54 100 157 17 182 93 75 63 24 168 25 189 84 156 201 118 156 105 96 112 201 22 134 139 114 116 145 175 11 121 198 99 40 151 34 72 117 52 190 105 90 20 118 60 83 52 208 205 181 209 16 174 122 206 70 202 144 71 18 208 8 66 38 135 170 178 53 115 5 138 88 123 17 200 115 119 182 98 9 87 97 102 72 3 8 180 82 145 56 33 165 102 173 96 213 157 12 33 69 80 129 192 2 101 165 203 51 86 190 87 193 124 116 122 4 21 7 53 211 27 104 207 197 73 125 23 59 176 37 114 111 74 151 153 50 73 148 116 127 153 45 2 124 121 193 28 16 78 100 162 166 128 88 9 188 53 92 49 148 111 193 129 187 68 77 92 54 4 135 51 63 19 97 1 194 150 31 35 194 132 9 206 75 58 168 144 167 118 37 127 62 94 60 78 196 47 132 110 162 65 35 98 32 43 87 1 2 106 21 12 124 20 22 38 117 148 212 149 119 164 76 180 183 101 46 10 95 205 186 143 40 32 56 38 21 126 31 30 123 108 151 135 165 107 29 120 71 13 137 62 208 104 88 4 39 29 19 115 23 160 54 105 91 41 177 27 200 14 163 192 121 79 199 84 55 30 128 179 175 130 99 17 195 44 95 187 164 99 136 173 191 113 108 37 13 18 84 174 8 84 60 179 74 37 109 40 50 78 82 140 122 9 92 168 48 145 74 55 131 6 169 152 60 202 30 27 86 185 16 169 51 182 212 53 97 185 ^ 452 1 82 181 121 167 132 198 92 48 72 119 57 114 184 200 81 68 122 39 26 84 96 26 80 1 208 177 217 24 44 191 206 118 209 123 8 140 99 128 99 54 109 42 58 83 80 122 113 141 96 147 203 183 180 175 158 16 143 155 155 11 1 13 64 23 1 87 54 35 52 46 157 121 19 27 174 115 130 209 72 123 152 150 87 202 140 76 23 75 77 66 86 11 149 118 88 44 168 101 94 14 80 145 93 165 73 65 66 12 21 137 192 4 22 83 201 120 77 113 94 181 195 157 144 124 51 151 33 211 38 131 178 186 138 184 5 61 92 99 175 107 6 155 81 114 207 87 105 45 40 120 73 18 58 60 193 98 11 98 15 100 51 3 146 187 61 88 97 139 204 129 189 73 213 171 36 216 55 55 51 174 138 17 15 49 41 15 197 146 39 174 64 120 3 123 82 37 111 179 58 157 70 134 39 100 74 108 170 164 197 169 144 198 41 163 84 170 16 92 145 167 155 85 116 25 208 200 104 48 21 16 69 40 143 178 42 35 196 56 145 70 60 49 88 23 149 192 78 12 95 127 204 55 199 61 162 212 151 130 88 74 34 180 152 53 210 166 112 74 182 67 176 30 35 29 159 133 19 101 164 127 56 168 175 84 26 131 104 196 126 40 46 83 6 7 101 90 12 44 24 216 106 158 39 30 179 132 147 82 60 216 203 35 75 151 181 98 62 108 3 49 185 25 185 95 80 71 103 153 22 106 88 144 54 156 175 10 129 119 178 19 148 172 79 102 207 13 208 33 114 36 95 57 91 79 176 104 25 41 210 92 122 62 131 108 73 162 161 48 142 14 33 137 141 119 34 9 160 5 38 205 75 198 189 50 108 147 59 173 192 8 117 119 104 122 136 28 120 124 28 46 9 16 213 50 131 34 83 150 17 89 164 53 66 156 124 125 141 45 137 215 109 46 60 119 201 124 172 149 215 183 36 72 170 67 102 133 23 196 200 30 58 9 183 110 62 182 211 61 18 202 163 97 ^ 463 1 45 50 116 145 8 64 204 150 74 93 184 89 111 39 108 108 85 61 13 36 154 61 210 115 3 84 108 22 152 209 216 103 176 123 126 57 183 10 199 107 186 161 105 51 38 69 184 26 202 15 171 57 97 77 24 90 33 183 167 70 83 29 110 67 49 123 63 148 159 190 148 2 99 172 159 33 160 26 139 3 44 17 46 89 40 101 87 62 69 27 38 6 55 2 162 184 183 190 211 131 6 212 210 138 144 132 85 124 25 60 91 112 95 99 212 30 126 120 195 34 19 158 71 28 211 217 56 167 7 71 122 70 66 79 65 134 27 61 147 103 199 44 57 137 65 50 202 78 80 81 137 128 12 177 22 129 68 168 23 74 30 55 182 174 208 3 21 96 218 112 158 111 16 187 177 5 179 140 82 59 52 188 36 20 214 62 29 156 62 46 106 107 29 70 129 91 89 174 51 15 45 136 49 100 142 217 182 88 55 48 4 163 20 174 74 156 196 113 151 90 96 92 191 7 134 134 94 106 130 170 1 106 193 79 25 146 24 67 112 32 190 85 210 75 15 108 45 73 37 193 205 166 194 1 169 102 206 65 197 129 51 218 198 208 66 33 120 155 163 43 95 5 133 78 103 2 185 105 114 167 93 4 77 87 102 57 3 218 175 67 135 56 18 165 92 168 86 203 157 212 13 59 75 109 187 217 96 155 203 31 71 185 82 193 119 116 122 204 16 7 48 201 22 89 197 192 63 125 18 39 171 17 109 101 64 141 138 50 53 133 101 127 153 45 207 104 121 188 13 216 63 85 147 166 108 68 214 188 53 87 39 148 96 178 124 182 48 67 72 44 214 125 41 63 219 97 211 194 135 16 30 189 132 219 191 70 43 158 134 157 118 37 107 52 94 60 68 191 47 122 110 157 55 25 83 12 43 72 201 202 101 1 12 114 10 2 28 117 138 207 144 109 164 76 165 178 101 41 90 190 171 143 30 32 41 23 11 121 31 25 123 103 136 135 150 97 14 115 66 213 132 62 203 94 83 209 19 24 4 100 8 150 160 ^ 474 0 105 91 20 156 27 193 208 142 178 107 79 199 84 41 2 128 165 161 109 85 17 174 37 81 187 150 78 129 159 194 184 92 87 23 214 18 77 153 209 63 46 179 46 30 102 33 29 50 82 126 101 203 78 147 20 138 53 27 117 207 148 145 32 181 16 13 86 178 16 162 30 175 198 32 90 99 66 177 113 155 124 186 80 44 60 119 49 106 176 192 65 52 106 27 26 68 92 14 80 211 200 169 213 24 44 191 202 102 197 111 140 99 124 95 54 97 42 54 79 68 110 97 133 80 135 199 175 180 171 146 8 131 147 151 221 219 9 52 15 1 79 50 27 44 42 145 105 15 19 162 103 118 201 72 107 152 142 87 190 132 68 19 71 77 62 70 7 137 114 76 214 36 160 97 78 220 76 141 93 157 57 61 58 9 125 180 4 6 67 189 120 61 113 82 181 183 153 136 120 43 139 29 199 26 123 174 186 138 184 1 61 76 83 175 107 6 143 81 114 207 75 89 29 32 108 73 10 46 48 185 86 11 98 221 88 35 221 146 175 49 88 93 139 196 117 189 65 201 163 24 208 51 39 51 170 134 1 3 49 33 11 189 138 35 166 64 116 213 115 70 25 111 167 58 149 66 122 31 96 66 104 170 152 197 169 140 190 41 151 72 162 12 92 145 163 155 69 104 21 208 200 96 48 21 4 61 40 139 178 34 23 196 44 133 62 52 33 84 23 141 184 74 4 79 123 192 47 191 53 158 200 151 130 80 62 34 172 140 41 206 154 112 70 174 55 164 18 19 13 159 121 19 89 160 115 52 164 167 76 10 119 104 188 126 28 38 75 220 3 85 90 8 40 8 204 90 154 39 14 171 128 147 78 56 216 191 35 75 147 169 82 50 100 209 45 185 13 177 95 72 71 95 145 14 98 72 144 38 148 163 6 125 107 170 3 140 172 67 98 203 5 204 17 98 36 87 41 75 71 168 88 17 25 202 84 114 58 131 92 69 162 161 36 142 14 25 129 141 111 18 1 152 215 30 193 59 198 181 34 96 139 47 173 192 214 109 103 100 118 128 16 104 112 198 ^ 466 0 25 2 213 213 36 124 13 62 150 221 61 150 39 45 149 124 104 134 38 130 208 109 18 32 112 201 96 158 149 215 176 22 44 149 39 88 133 220 189 193 23 44 9 183 89 48 161 204 54 222 195 163 167 40 45 106 140 8 49 204 145 69 83 169 89 96 24 93 103 85 41 3 31 154 51 210 115 213 79 108 12 147 209 206 103 176 113 116 37 173 10 189 102 176 156 100 36 33 69 174 16 202 5 171 52 82 72 4 80 23 178 162 70 83 29 105 67 34 118 43 143 154 185 138 2 79 157 149 33 160 21 129 208 24 2 31 69 35 81 72 47 64 22 38 221 55 222 152 179 168 180 211 121 1 207 200 133 129 117 80 114 25 50 76 102 85 84 212 30 111 110 195 29 14 153 51 28 196 212 36 167 222 61 107 55 46 64 65 119 220 12 56 137 93 194 29 57 137 50 210 30 197 78 65 71 132 123 7 177 22 129 68 168 3 74 10 50 167 174 198 218 6 86 218 97 158 106 6 177 162 210 164 125 62 59 52 173 16 20 214 42 9 141 57 46 106 97 24 50 119 86 84 169 46 15 25 136 44 100 127 202 182 83 35 33 209 158 15 159 64 156 191 108 146 75 96 72 181 217 134 129 74 96 115 165 216 91 188 59 10 141 14 62 107 12 190 65 205 60 10 98 30 63 22 178 205 151 179 211 164 82 206 60 192 114 31 203 188 193 66 28 105 140 148 33 75 5 128 68 83 212 170 95 109 152 88 224 67 77 102 42 3 213 170 52 125 56 3 165 82 163 76 193 157 197 218 49 70 89 182 217 91 145 203 11 56 180 77 193 114 116 122 189 11 7 43 191 17 74 187 187 53 125 13 19 166 222 104 91 54 131 123 50 33 118 86 127 153 45 197 84 121 183 223 201 48 70 132 166 88 48 204 188 53 82 29 148 81 163 119 177 28 57 52 34 209 115 31 63 204 97 206 194 120 1 25 184 132 214 176 65 28 148 124 147 118 37 87 42 94 60 58 186 47 112 110 152 45 15 68 217 43 57 186 187 218 ^ 477 1 200 12 100 223 201 14 117 124 200 137 95 164 76 144 171 101 34 213 83 169 150 143 16 32 20 2 224 114 31 18 123 96 115 135 129 83 220 108 59 192 125 62 196 80 76 195 218 17 210 79 214 136 6 105 91 5 141 27 188 193 127 168 97 79 199 84 31 209 128 155 151 94 75 17 159 32 71 187 140 63 124 149 179 179 77 72 13 204 18 72 138 199 48 36 179 26 25 97 28 14 30 82 116 86 188 68 132 133 38 7 107 197 133 140 12 166 6 3 86 173 16 157 15 170 188 17 85 84 46 172 103 140 114 171 65 39 45 119 39 96 166 182 45 32 86 12 26 48 87 226 80 201 190 159 208 24 44 191 197 82 182 96 217 140 99 119 90 54 82 42 49 74 53 95 77 123 60 120 194 165 180 166 131 225 116 137 146 211 219 4 37 5 1 69 45 17 34 37 130 85 10 9 147 88 103 191 72 87 152 132 87 175 122 58 14 66 77 57 50 2 122 109 61 209 26 150 92 58 205 71 136 93 147 37 56 48 212 221 110 165 4 213 47 174 120 41 113 67 181 168 148 126 115 33 124 24 184 11 113 169 186 138 184 223 61 56 63 175 107 6 128 81 114 207 60 69 9 22 93 73 31 33 175 71 11 98 206 73 15 221 146 160 34 88 88 139 186 102 189 55 186 153 9 198 46 19 51 165 129 208 215 49 23 6 179 128 30 156 64 111 203 105 55 10 111 152 58 139 61 107 21 91 56 99 170 137 197 169 135 180 41 136 57 152 7 92 145 158 155 49 89 16 208 200 86 48 21 216 51 40 134 178 24 8 196 29 118 52 42 13 79 23 131 174 69 221 59 118 177 37 181 43 153 185 151 130 70 47 34 162 125 26 201 139 112 65 164 40 149 3 226 220 159 106 19 74 155 100 47 159 157 66 217 104 104 178 126 13 28 65 215 225 65 90 3 35 215 189 70 149 39 221 161 123 147 73 51 216 176 35 75 142 154 62 35 90 194 40 185 225 167 95 62 71 85 135 4 88 52 144 18 138 148 1 120 92 160 210 130 172 52 93 198 222 199 224 19 ^ 479 0 36 73 13 47 57 154 60 3 226 188 70 100 51 131 64 62 162 161 15 142 14 11 115 141 97 219 216 138 201 16 172 31 198 167 6 75 125 26 173 192 193 95 75 93 111 114 224 76 91 213 13 227 201 213 28 120 1 50 150 213 45 142 31 33 145 124 92 130 34 126 204 109 2 16 108 201 80 150 149 215 172 14 28 137 23 80 133 208 185 189 19 36 9 183 77 40 149 200 50 214 191 163 159 36 41 98 136 8 37 204 141 65 75 157 89 84 12 81 99 85 25 224 27 154 43 210 115 205 75 108 4 143 209 198 103 176 105 108 21 165 10 181 98 168 152 96 24 29 69 166 8 202 226 171 48 70 68 217 72 15 174 158 70 83 29 101 67 22 114 27 139 150 181 130 2 63 145 141 33 160 17 121 196 8 219 19 53 31 65 60 35 60 18 38 217 55 222 144 175 156 172 211 113 226 203 192 129 117 105 76 106 25 42 64 94 77 72 212 30 99 102 195 25 10 149 35 28 184 208 20 167 218 53 95 43 30 52 65 107 220 52 129 85 190 17 57 137 38 202 14 193 78 53 63 128 119 3 177 22 129 68 168 216 74 223 46 155 174 190 214 223 78 218 85 158 102 227 169 150 198 152 113 46 59 52 161 20 214 26 222 129 53 46 106 89 20 34 111 82 80 165 42 15 9 136 40 100 115 190 182 79 19 21 197 154 11 147 56 156 187 104 142 63 96 56 173 209 134 125 58 88 103 161 212 79 184 43 227 137 6 58 103 225 190 49 201 48 6 90 18 55 10 166 205 139 167 203 160 66 206 56 188 102 15 191 180 181 66 24 93 128 136 25 59 5 124 60 67 204 158 87 105 140 84 224 59 69 102 30 3 209 166 40 117 56 220 165 74 159 68 185 157 185 206 41 66 73 178 217 87 137 203 224 44 176 73 193 110 116 122 177 7 7 39 183 13 62 179 183 45 125 9 3 162 210 100 83 46 123 111 50 17 106 74 127 153 45 189 68 121 179 215 189 36 58 120 166 72 32 196 188 53 78 21 148 69 151 115 173 12 49 36 26 205 107 23 63 192 112 ^ 485 1 200 194 102 214 19 178 132 208 158 59 10 136 112 135 118 37 63 30 94 60 46 180 47 100 110 146 33 3 50 199 43 39 168 169 90 188 12 92 219 189 6 117 116 196 133 87 164 76 132 167 101 30 209 79 157 138 143 8 32 8 221 220 110 31 14 123 92 103 135 117 75 212 104 55 180 121 62 192 72 72 187 206 13 202 67 206 128 221 105 91 224 129 27 184 181 115 160 89 79 199 84 23 197 128 147 143 82 67 17 147 28 63 187 132 51 120 141 167 175 65 60 5 196 18 68 126 191 36 28 179 10 21 93 24 2 14 82 108 74 176 60 120 215 129 26 222 99 189 121 136 227 154 229 226 86 169 16 153 3 166 180 5 81 72 30 168 95 128 106 159 53 35 33 119 31 88 158 174 29 16 70 26 32 83 218 80 193 182 151 204 24 44 191 193 66 170 84 213 140 99 115 86 54 70 42 45 70 41 83 61 115 44 108 190 157 180 162 119 221 104 129 142 203 219 25 228 1 61 41 9 26 33 118 69 6 1 135 76 91 183 72 71 152 124 87 163 114 50 10 62 77 53 34 229 110 105 49 205 18 142 88 42 193 67 132 93 139 21 52 40 204 213 98 153 4 201 31 162 120 25 113 55 181 156 144 118 111 25 112 20 172 230 105 165 186 138 184 223 61 40 47 175 107 6 116 81 114 207 48 53 224 14 81 73 223 19 21 167 59 11 98 194 61 230 221 146 148 22 88 84 139 178 90 189 47 174 145 228 190 42 3 51 161 125 196 207 49 15 2 171 120 26 148 64 107 195 97 43 229 111 140 58 131 57 95 13 87 48 95 170 125 197 169 131 172 41 124 45 144 3 92 145 154 155 33 77 12 208 200 78 48 21 208 43 40 130 178 16 227 196 17 106 44 34 228 75 23 123 166 65 217 43 114 165 29 173 35 149 173 151 130 62 35 34 154 113 14 197 127 112 61 156 28 137 222 214 208 159 94 19 62 151 88 43 155 149 58 205 92 104 170 126 1 20 57 211 225 49 90 230 31 203 177 54 145 39 209 153 119 147 69 47 216 164 35 75 138 142 46 23 82 182 36 185 198 ^ 483 1 155 95 50 71 73 123 225 76 28 144 227 126 130 228 114 74 148 192 118 172 34 87 192 216 193 206 54 36 65 230 31 49 146 44 228 214 180 62 92 47 131 48 58 162 161 3 142 14 3 107 141 89 207 212 130 193 8 160 15 198 159 223 63 117 14 173 192 181 87 59 89 107 106 216 60 79 201 1 227 189 213 20 116 222 38 150 205 29 134 23 21 141 124 80 126 30 122 200 109 219 104 201 64 142 149 215 168 6 12 125 7 72 133 196 181 185 15 28 9 183 65 32 137 196 46 206 187 163 151 32 37 90 132 8 25 204 137 61 67 145 89 72 69 95 85 9 220 23 154 35 210 115 197 71 108 229 139 209 190 103 176 97 100 5 157 10 173 94 160 148 92 12 25 69 158 202 222 171 44 58 64 205 64 7 170 154 70 83 29 97 67 10 110 11 135 146 177 122 2 47 133 133 33 160 13 113 184 225 211 7 37 27 49 48 23 56 14 38 213 55 222 136 171 144 164 211 105 226 199 184 125 105 93 72 98 25 34 52 86 69 60 212 30 87 94 195 21 6 145 19 28 172 204 4 167 214 45 83 31 14 40 65 95 220 221 48 121 77 186 5 57 137 26 194 231 189 78 41 55 124 115 232 177 22 129 68 168 204 74 211 42 143 174 182 210 215 70 218 73 158 98 223 161 138 186 140 101 30 59 52 149 217 20 214 10 210 117 49 46 106 81 16 18 103 78 76 161 38 15 226 136 36 100 103 178 182 75 3 9 185 150 7 135 48 156 183 100 138 51 96 40 165 201 134 121 42 80 91 157 208 67 180 27 219 133 231 54 99 213 190 33 197 36 2 82 6 47 231 154 205 127 155 195 156 50 206 52 184 90 232 179 172 169 66 20 81 116 124 17 43 5 120 52 51 196 146 79 101 128 80 224 51 61 102 18 3 205 162 28 109 56 212 165 66 155 60 177 157 173 194 33 62 57 174 217 83 129 203 212 32 172 69 193 106 116 122 165 3 7 35 175 9 50 171 179 37 125 5 220 158 198 96 75 38 115 99 50 1 94 62 127 153 45 181 52 121 175 207 177 24 46 108 164 ^ 499 0 44 4 182 188 53 71 7 148 48 130 108 166 220 35 8 12 198 93 9 63 171 97 195 194 87 204 14 173 132 203 143 54 231 126 102 125 118 37 43 20 94 60 36 175 47 90 110 141 23 229 35 184 43 24 153 154 85 173 12 82 214 174 232 117 106 191 128 77 164 76 117 162 101 25 204 74 142 123 143 234 32 229 211 215 105 31 9 123 87 88 135 102 65 202 99 50 165 116 62 187 62 67 177 191 8 192 52 196 118 206 105 91 214 114 27 179 166 100 150 79 79 199 84 13 182 128 137 133 67 57 17 132 23 53 187 122 36 115 131 152 170 50 45 231 186 18 63 111 181 21 18 179 226 16 88 19 223 230 82 98 59 161 50 105 200 124 11 207 89 179 106 131 212 139 224 221 86 164 16 148 224 161 170 226 76 57 10 163 85 113 96 144 38 30 18 119 21 78 148 164 9 232 50 221 26 12 78 208 80 183 172 141 199 24 44 191 188 46 155 69 208 140 99 110 81 54 55 42 40 65 26 68 41 105 24 93 185 147 180 157 104 216 89 119 137 193 219 231 10 223 1 51 36 235 16 28 103 49 1 227 120 61 76 173 72 51 152 114 87 148 104 40 5 57 77 48 14 229 95 100 34 200 8 132 83 22 178 62 127 93 129 1 47 30 194 203 83 138 4 186 11 147 120 5 113 40 181 141 139 108 106 15 97 15 157 220 95 160 186 138 184 223 61 20 27 175 107 6 101 81 114 207 33 33 209 4 66 73 218 4 6 157 44 11 98 179 46 215 221 146 133 7 88 79 139 168 75 189 37 159 135 218 180 37 219 51 156 120 181 197 49 5 233 161 110 21 138 64 102 185 87 28 219 111 125 58 121 52 80 3 82 38 90 170 110 197 169 126 162 41 109 30 134 234 92 145 149 155 13 62 7 208 200 68 48 21 198 33 40 125 178 6 217 196 2 91 34 24 213 70 23 113 156 60 212 23 109 150 19 163 25 144 158 151 130 52 20 34 144 98 235 192 112 112 56 146 13 122 212 199 193 159 79 19 47 146 73 38 150 139 48 190 77 104 160 126 222 10 47 206 225 29 90 230 26 188 162 34 140 39 194 143 114 147 64 42 216 149 174 ^ 473 1 75 131 121 18 2 68 161 29 185 203 145 95 40 71 63 113 220 66 8 144 212 116 115 228 109 59 138 177 108 172 19 82 187 211 188 191 34 36 55 215 11 39 136 24 223 199 170 52 82 42 131 28 53 162 161 226 142 14 231 97 141 79 192 207 120 183 236 145 233 198 149 208 48 107 237 173 192 166 77 39 84 102 96 206 40 64 186 224 227 174 213 10 111 212 23 150 195 9 124 13 6 136 124 65 121 25 117 195 109 204 218 99 201 44 132 149 215 163 234 230 110 225 62 133 181 176 180 10 18 9 183 50 22 122 191 41 196 182 163 141 27 32 80 127 8 10 204 132 56 57 130 89 57 223 54 90 85 227 215 18 154 25 210 115 187 66 108 224 134 209 180 103 176 87 90 223 147 10 163 89 150 143 87 235 20 69 148 228 202 217 171 39 43 59 190 54 235 165 149 70 83 29 92 67 233 105 229 130 141 172 112 2 27 118 123 33 160 8 103 169 210 201 230 17 22 29 33 8 51 9 38 208 55 222 126 166 129 154 211 95 226 194 174 120 90 78 67 88 25 24 37 76 59 45 212 30 72 84 195 16 1 140 237 28 157 199 222 167 209 35 68 16 232 25 65 80 220 211 43 111 67 181 228 57 137 11 184 216 184 78 26 45 119 110 232 177 22 129 68 168 189 74 196 37 128 174 172 205 205 60 218 58 158 93 218 151 123 171 125 86 10 59 52 134 202 20 214 228 195 102 44 46 106 71 11 236 93 73 71 156 33 15 211 136 31 100 88 163 182 70 221 232 170 145 2 120 38 156 178 95 133 36 96 20 155 191 134 116 22 70 76 152 203 52 175 7 209 128 226 49 94 198 190 13 192 21 235 72 229 37 221 139 205 112 140 185 151 30 206 47 179 75 217 164 162 154 66 15 66 101 109 7 23 5 115 42 31 186 131 69 96 113 75 224 41 51 102 3 3 200 157 13 99 56 202 165 56 150 50 167 157 158 179 23 57 37 169 217 78 119 203 197 17 167 64 193 101 116 122 150 236 7 30 165 4 35 161 174 27 125 205 153 148 ^ 502 1 89 61 24 101 78 50 213 73 41 127 153 45 167 24 121 168 193 156 3 25 87 166 28 228 174 188 53 67 239 148 36 118 104 162 208 27 232 4 194 85 1 63 159 97 191 194 75 196 10 169 132 199 131 50 223 118 94 117 118 37 27 12 94 60 28 171 47 82 110 137 15 225 23 172 43 12 141 142 81 161 12 74 210 162 228 117 98 187 124 69 164 76 105 158 101 21 200 70 130 111 143 230 32 221 203 211 101 31 5 123 83 76 135 90 57 194 95 46 153 112 62 183 54 63 169 179 4 184 40 188 110 194 105 91 206 102 27 175 154 88 142 71 79 199 84 5 170 128 129 125 55 49 17 120 19 45 187 114 24 111 123 140 166 38 33 227 178 18 59 99 173 9 10 179 214 12 84 15 215 218 82 90 47 149 42 93 188 120 239 195 81 171 94 127 200 127 220 217 86 160 16 144 216 157 162 218 72 45 234 159 77 101 88 132 26 26 6 119 13 70 140 156 233 220 34 213 26 236 74 200 80 175 164 133 195 24 44 191 184 30 143 57 204 140 99 106 77 54 43 42 36 61 14 56 25 97 8 81 181 139 180 153 92 212 77 111 133 185 219 231 238 219 1 43 32 231 8 24 91 33 237 223 108 49 64 165 72 35 152 106 87 136 96 32 1 53 77 44 238 229 83 96 22 196 124 79 6 166 58 123 93 121 225 43 22 186 195 71 126 4 174 235 135 120 229 113 28 181 129 135 100 102 7 85 11 145 212 87 156 186 138 184 223 61 4 11 175 107 6 89 81 114 207 21 17 197 236 54 73 214 232 234 149 32 11 98 167 34 203 221 146 121 235 88 75 139 160 63 189 29 147 127 210 172 33 207 51 152 116 169 189 49 237 233 153 102 17 130 64 98 177 79 16 211 111 113 58 113 48 68 235 78 30 86 170 98 197 169 122 154 41 97 18 126 234 92 145 145 155 237 50 3 208 200 60 48 21 190 25 40 121 178 238 209 196 230 79 26 16 201 66 23 105 148 56 208 7 105 138 11 155 17 140 146 151 130 44 8 34 136 86 227 188 100 112 52 138 1 110 204 187 181 159 67 19 35 142 61 34 146 131 40 178 65 104 152 126 214 2 39 202 173 ^ 486 1 5 90 230 20 170 144 10 134 39 176 131 108 147 58 36 216 131 35 75 127 109 2 232 60 149 25 185 195 137 95 32 71 55 105 216 58 234 144 200 108 103 228 105 47 130 165 100 172 7 78 183 207 184 179 18 36 47 203 237 31 128 8 219 187 162 44 74 38 131 12 49 162 161 218 142 14 227 89 141 71 180 203 112 175 232 133 221 198 141 196 36 99 229 173 192 154 69 23 80 98 88 198 24 52 174 216 227 162 213 2 107 204 11 150 187 235 116 5 236 132 124 53 117 21 113 191 109 192 206 95 201 28 124 149 215 159 230 218 98 213 54 133 169 172 176 6 10 9 183 38 14 110 187 37 188 178 163 133 23 28 72 123 8 240 204 128 52 49 118 89 45 215 42 86 85 215 211 14 154 17 210 115 179 62 108 220 130 209 172 103 176 79 82 211 139 10 155 85 142 139 83 227 16 69 140 224 202 213 171 35 31 55 178 46 231 161 145 70 83 29 88 67 225 101 217 126 137 168 104 2 11 106 115 33 160 4 95 157 198 193 222 1 18 13 21 238 47 5 38 204 55 222 118 162 117 146 211 87 226 190 166 116 78 66 63 80 25 16 25 68 51 33 212 30 60 76 195 12 239 136 225 28 145 195 210 167 205 27 56 4 220 13 65 68 220 203 39 103 59 177 220 57 137 241 176 204 180 78 14 37 115 106 232 177 22 129 68 168 177 74 184 33 116 174 164 201 197 52 218 46 158 89 214 143 111 159 113 74 236 59 52 122 190 20 214 216 183 90 40 46 106 63 7 224 85 69 67 152 29 15 199 136 27 100 76 151 182 66 209 224 158 141 240 108 30 156 174 91 129 24 96 4 147 183 134 112 6 62 64 148 199 40 171 233 201 124 222 45 90 186 190 239 188 9 235 64 221 29 213 127 205 100 128 177 147 14 206 43 175 63 205 152 154 142 66 11 54 89 97 241 7 5 111 34 15 178 119 61 92 101 71 224 33 43 102 233 3 196 153 1 91 56 194 165 48 146 42 159 157 146 167 15 53 21 165 217 74 111 203 185 5 163 60 193 97 116 122 138 236 7 26 157 23 153 170 184 ^ 505 1 125 238 187 147 165 85 53 16 93 66 50 201 61 29 127 153 45 159 8 121 164 185 144 235 13 75 166 12 216 166 188 53 63 235 148 24 106 100 158 196 19 220 240 190 77 237 63 147 97 187 194 63 188 6 165 132 195 119 46 215 110 86 109 118 37 11 4 94 60 20 167 47 74 110 133 7 221 11 160 43 129 130 77 149 12 66 206 150 224 117 90 183 120 61 164 76 93 154 101 17 196 66 118 99 143 226 32 213 195 207 97 31 1 123 79 64 135 78 49 186 91 42 141 108 62 179 46 59 161 167 176 28 180 102 182 105 91 198 90 27 171 142 76 134 63 79 199 84 241 158 128 121 117 43 41 17 108 15 37 187 106 12 107 115 128 162 26 21 223 170 18 55 87 165 241 2 179 202 8 80 11 207 206 82 82 35 137 34 81 176 116 231 183 73 163 82 123 188 115 216 213 86 156 16 140 208 153 154 210 68 33 222 155 69 89 80 120 14 22 238 119 5 62 132 148 221 208 18 205 26 224 70 192 80 167 156 125 191 24 44 191 180 14 131 45 200 140 99 102 73 54 31 42 32 57 2 44 9 89 236 69 177 131 180 149 80 208 65 103 129 177 219 231 230 215 1 35 28 227 20 79 17 237 219 96 37 52 157 72 19 152 98 87 124 88 24 241 49 77 40 226 229 71 92 10 192 236 116 75 234 154 54 119 93 113 213 39 14 178 187 59 114 4 162 223 123 120 217 113 16 181 117 131 92 98 243 73 7 133 204 79 152 186 138 184 223 61 232 239 175 107 6 77 81 114 207 9 1 185 232 42 73 210 224 226 141 20 11 98 155 22 191 221 146 109 227 88 71 139 152 51 189 21 135 119 202 164 29 195 51 148 112 157 181 49 233 233 145 94 13 122 64 94 169 71 4 203 111 101 58 105 44 56 231 74 22 82 170 86 197 169 118 146 41 85 6 118 234 92 145 141 155 225 38 243 208 200 52 48 21 182 17 40 117 178 234 201 196 222 67 18 8 189 62 23 97 140 52 204 235 101 126 3 147 9 136 134 151 130 36 240 34 128 74 219 184 88 112 48 130 233 98 196 175 169 159 55 19 23 138 49 30 142 123 32 166 53 104 144 126 206 238 31 198 203 ^ 483 1 235 90 230 16 158 132 240 130 39 164 123 104 147 54 32 216 119 35 75 123 97 232 224 52 137 21 185 187 129 95 24 71 47 97 212 50 222 144 188 100 91 228 101 35 122 153 92 172 241 74 179 203 180 167 2 36 39 191 225 23 120 238 215 175 154 36 66 34 131 242 45 162 161 210 142 14 223 81 141 63 168 199 104 167 228 121 209 198 133 184 24 91 221 173 192 142 61 7 76 94 80 190 8 40 162 208 227 150 213 240 103 196 245 150 179 223 108 243 228 128 124 41 113 17 109 187 109 180 194 91 201 12 116 149 215 155 226 206 86 201 46 133 157 168 172 2 2 9 183 26 6 98 183 33 180 174 163 125 19 24 64 119 8 232 204 124 48 41 106 89 33 207 30 82 85 203 207 10 154 9 210 115 171 58 108 216 126 209 164 103 176 71 74 199 131 10 147 81 134 135 79 219 12 69 132 220 202 209 171 31 19 51 166 38 227 157 141 70 83 29 84 67 217 97 205 122 133 164 96 2 241 94 107 33 160 87 145 186 185 214 231 14 243 9 230 43 1 38 200 55 222 110 158 105 138 211 79 226 186 158 112 66 54 59 72 25 8 13 60 43 21 212 30 48 68 195 8 239 132 213 28 133 191 198 167 201 19 44 238 208 1 65 56 220 195 35 95 51 173 212 57 137 233 168 192 176 78 2 29 111 102 232 177 22 129 68 168 165 74 172 29 104 174 156 197 189 44 218 34 158 85 210 135 99 147 101 62 224 59 52 110 178 20 214 204 171 78 36 46 106 55 3 212 77 65 63 148 25 15 187 136 23 100 64 139 182 62 197 216 146 137 240 96 22 156 170 87 125 12 96 234 139 175 134 108 236 54 52 144 195 28 167 221 193 120 218 41 86 174 190 227 184 243 235 56 213 21 205 115 205 88 116 169 143 244 206 39 171 51 193 140 146 130 66 7 42 77 85 237 237 5 107 26 245 170 107 53 88 89 67 224 25 35 102 225 3 192 149 235 83 56 186 165 40 142 34 151 157 134 155 7 49 5 161 217 70 103 203 173 239 159 56 193 93 116 122 126 236 7 22 149 242 178 ^ 507 1 141 164 7 125 238 175 143 153 81 45 8 85 54 50 189 49 17 127 153 45 151 240 121 160 177 132 227 1 63 166 244 204 158 188 53 59 231 148 12 94 96 154 184 11 208 236 186 69 233 63 135 97 183 194 51 180 2 161 132 191 107 42 207 102 78 101 118 37 243 244 94 60 12 163 47 66 110 129 247 217 247 148 43 236 117 118 73 137 12 58 202 138 220 117 82 179 116 53 164 76 81 150 101 13 192 62 106 87 143 222 32 205 187 203 93 31 245 123 75 52 135 66 41 178 87 38 129 104 62 175 38 55 153 155 244 168 16 172 94 170 105 91 190 78 27 167 130 64 126 55 79 199 84 237 146 128 113 109 31 33 17 96 11 29 187 98 103 107 116 158 14 9 219 162 18 51 75 157 233 242 179 190 4 76 7 199 194 82 74 23 125 26 69 164 112 223 171 65 155 70 119 176 103 212 209 86 152 16 136 200 149 146 202 64 21 210 151 61 77 72 108 2 18 230 119 245 54 124 140 209 196 2 197 26 212 66 184 80 159 148 117 187 24 44 191 176 246 119 33 196 140 99 98 69 54 19 42 28 53 238 32 241 81 224 57 173 123 180 145 68 204 53 95 125 169 219 231 222 211 1 27 24 223 240 16 67 1 237 215 84 25 40 149 72 3 152 90 87 112 80 16 241 45 77 36 214 229 59 88 246 188 232 108 71 222 142 50 115 93 105 201 35 6 170 179 47 102 4 150 211 111 120 205 113 4 181 105 127 84 94 239 61 3 121 196 71 148 186 138 184 223 61 220 227 175 107 6 65 81 114 207 245 233 173 228 30 73 206 216 218 133 8 11 98 143 10 179 221 146 97 219 88 67 139 144 39 189 13 123 111 194 156 25 183 51 144 108 145 173 49 229 233 137 86 9 114 64 90 161 63 240 195 111 89 58 97 40 44 227 70 14 78 170 74 197 169 114 138 41 73 242 110 234 92 145 137 155 213 26 243 208 200 44 48 21 174 9 40 113 178 230 193 196 214 55 10 177 58 23 89 132 48 200 223 97 114 243 139 1 132 122 151 130 28 232 34 120 62 211 180 76 112 44 122 225 86 188 163 157 159 43 19 11 134 37 26 138 115 24 154 41 104 136 126 198 234 140 ^ 490 1 192 225 223 90 230 12 146 120 228 126 39 152 115 100 147 50 28 216 107 35 75 119 85 220 216 44 125 17 185 179 121 95 16 71 39 89 208 42 210 144 176 92 79 228 97 23 114 141 84 172 233 70 175 199 176 155 236 36 31 179 213 15 112 226 211 163 146 28 58 30 131 230 41 162 161 202 142 14 219 73 141 55 156 195 96 159 224 109 197 198 125 172 12 83 213 173 192 130 53 241 72 90 72 182 242 28 150 200 227 138 213 236 99 188 237 150 171 211 100 239 220 124 124 29 109 13 105 183 109 168 182 87 201 246 108 149 215 151 222 194 74 189 38 133 145 164 168 248 244 9 183 14 248 86 179 29 172 170 163 117 15 20 56 115 8 224 204 120 44 33 94 89 21 199 18 78 85 191 203 6 154 1 210 115 163 54 108 212 122 209 156 103 176 63 66 187 123 10 139 77 126 131 75 211 8 69 124 216 202 205 171 27 7 47 154 30 223 153 137 70 83 29 80 67 209 93 193 118 129 160 88 2 229 82 99 33 160 246 79 133 174 177 206 219 10 231 247 222 39 247 38 196 55 222 102 154 93 130 211 71 226 182 150 108 54 42 55 64 25 1 52 35 9 212 30 36 60 195 4 239 128 201 28 121 187 186 167 197 11 32 230 196 239 65 44 220 187 31 87 43 169 204 57 137 225 160 180 172 78 240 21 107 98 232 177 22 129 68 168 153 74 160 25 92 174 148 193 181 36 218 22 158 81 206 127 87 135 89 50 212 59 52 98 166 20 214 192 159 66 32 46 106 47 249 200 69 61 59 144 21 15 175 136 19 100 52 127 182 58 185 208 134 133 240 84 14 156 166 83 121 96 222 131 167 134 104 224 46 40 140 191 16 163 209 185 116 214 37 82 162 190 215 180 235 235 48 205 13 197 103 205 76 104 161 139 232 206 35 167 39 181 128 138 118 66 3 30 65 73 233 225 5 103 18 233 162 95 45 84 77 63 224 17 27 102 217 3 188 145 227 75 56 178 165 32 138 26 143 157 122 143 249 45 239 157 217 66 95 203 161 231 155 52 193 89 116 122 114 236 7 18 141 242 249 137 162 3 125 238 69 ^ 514 1 139 141 77 37 77 42 50 177 37 5 127 153 45 143 228 121 156 169 120 219 241 51 166 232 192 150 188 53 55 227 148 82 92 150 172 3 196 232 182 61 229 63 123 97 179 194 39 172 250 157 132 187 95 38 199 94 70 93 118 37 231 240 94 60 4 159 47 58 110 125 243 213 239 136 43 228 105 106 69 125 12 50 198 126 216 117 74 175 112 45 164 76 69 146 101 9 188 58 94 75 143 218 32 197 179 199 89 31 245 123 71 40 135 54 33 170 83 34 117 100 62 171 30 51 145 143 244 160 4 164 86 158 105 91 182 66 27 163 118 52 118 47 79 199 84 233 134 128 105 101 19 25 17 84 7 21 187 90 240 99 99 104 154 2 249 215 154 18 47 63 149 225 238 179 178 72 3 191 182 82 66 11 113 18 57 152 108 215 159 57 147 58 115 164 91 208 205 86 148 16 132 192 145 138 194 60 9 198 147 53 65 64 96 242 14 222 119 241 46 116 132 197 184 238 189 26 200 62 176 80 151 140 109 183 24 44 191 172 234 107 21 192 140 99 94 65 54 7 42 24 49 230 20 229 73 212 45 169 115 180 141 56 200 41 87 121 161 219 231 214 207 1 19 20 219 236 12 55 237 237 211 72 13 28 141 72 239 152 82 87 100 72 8 241 41 77 32 202 229 47 84 238 184 228 100 67 210 130 46 111 93 97 189 31 250 162 171 35 90 4 138 199 99 120 193 113 244 181 93 123 76 90 235 49 251 109 188 63 144 186 138 184 223 61 208 215 175 107 6 53 81 114 207 237 221 161 224 18 73 202 208 210 125 248 11 98 131 250 167 221 146 85 211 88 63 139 136 27 189 5 111 103 186 148 21 171 51 140 104 133 165 49 225 233 129 78 5 106 64 86 153 55 232 187 111 77 58 89 36 32 223 66 6 74 170 62 197 169 110 130 41 61 234 102 234 92 145 133 155 201 14 243 208 200 36 48 21 166 1 40 109 178 226 185 196 206 43 2 244 165 54 23 81 124 44 196 211 93 102 239 131 245 128 110 151 130 20 224 34 112 50 203 176 64 112 40 114 217 74 180 151 145 159 31 19 251 130 25 22 134 107 16 142 29 104 128 126 190 230 15 190 225 217 90 230 10 140 114 222 124 39 146 111 217 ^ 510 0 147 46 24 216 95 35 75 115 73 208 208 36 113 13 185 171 113 95 8 71 31 81 204 34 198 144 164 84 67 228 93 11 106 129 76 172 225 66 171 195 172 143 224 36 23 167 201 7 104 214 207 151 138 20 50 26 131 218 37 162 161 194 142 14 215 65 141 47 144 191 88 151 220 97 185 198 117 160 75 205 173 192 118 45 229 68 86 64 174 230 16 138 192 227 126 213 232 95 180 229 150 163 199 92 235 212 120 124 17 105 9 101 179 109 156 170 83 201 234 100 149 215 147 218 182 62 177 30 133 133 160 164 248 240 9 183 2 244 74 175 25 164 166 163 109 11 16 48 111 8 216 204 116 40 25 82 89 9 191 6 74 85 179 199 2 154 247 210 115 155 50 108 208 118 209 148 103 176 55 58 175 115 10 131 73 118 127 71 203 4 69 116 212 202 201 171 23 249 43 142 22 219 149 133 70 83 29 76 67 201 89 181 114 125 156 80 2 217 70 91 33 160 246 71 121 162 169 198 207 6 219 239 214 35 247 38 192 55 222 94 150 81 122 211 63 226 178 142 104 42 30 51 56 25 246 243 44 27 251 212 30 24 52 195 239 124 189 28 109 183 174 167 193 3 20 222 184 231 65 32 220 179 27 79 35 165 196 57 137 217 152 168 168 78 232 13 103 94 232 177 22 129 68 168 141 74 148 21 80 174 140 189 173 28 218 10 158 77 202 119 75 123 77 38 200 59 52 86 154 20 214 180 147 54 28 46 106 39 249 188 61 57 55 140 17 15 163 136 15 100 40 115 182 54 173 200 122 129 240 72 6 156 162 79 117 242 96 210 123 159 134 100 212 38 28 136 187 4 159 197 177 112 210 33 78 150 190 203 176 227 235 40 197 5 189 91 205 64 92 153 135 220 206 31 163 27 169 116 130 106 66 253 18 53 61 229 213 5 99 10 221 154 83 37 80 65 59 224 9 19 102 209 3 184 141 219 67 56 170 165 24 134 18 135 157 110 131 245 41 227 153 217 62 87 203 149 223 151 48 193 85 116 122 102 236 7 14 133 242 241 129 158 249 125 238 157 137 135 75 33 250 73 36 50 171 31 253 127 153 45 139 222 121 154 165 114 215 237 45 166 226 186 146 188 53 53 225 148 248 118 ^ 533 0 87 145 157 250 181 227 177 51 224 63 108 97 174 194 24 162 250 152 132 182 80 33 189 84 60 83 118 37 216 235 94 60 251 154 47 48 110 120 238 208 229 121 43 218 90 91 64 110 12 40 193 111 211 117 64 170 107 35 164 76 54 141 101 4 183 53 79 60 143 213 32 187 169 194 84 31 245 123 66 25 135 39 23 160 78 29 102 95 62 166 20 46 135 128 244 150 246 154 76 143 105 91 172 51 27 158 103 37 108 37 79 199 84 228 119 128 95 91 4 15 17 69 2 11 187 80 230 94 89 89 149 244 239 210 144 18 42 48 139 215 233 179 163 252 67 255 181 167 82 56 253 98 8 42 137 103 205 144 47 137 43 110 149 76 203 200 86 143 16 127 182 140 128 184 55 251 183 142 43 50 54 81 232 9 212 119 236 36 106 122 182 169 223 179 26 185 57 166 80 141 130 99 178 24 44 191 167 219 92 6 187 140 99 89 60 54 249 42 19 44 220 5 214 63 197 30 164 105 180 136 41 195 26 77 116 151 219 231 204 202 1 9 15 214 231 7 40 222 237 206 57 255 13 131 72 224 152 72 87 85 62 255 241 36 77 27 187 229 32 79 228 179 223 90 62 195 115 41 106 93 87 174 26 245 152 161 20 75 4 123 184 84 120 178 113 234 181 78 118 66 85 230 34 251 94 178 53 139 186 138 184 223 61 193 200 175 107 6 38 81 114 207 227 206 146 219 3 73 197 198 200 115 238 11 98 116 240 152 221 146 70 201 88 58 139 126 12 189 252 96 93 176 138 16 156 51 135 99 118 155 49 220 233 119 68 96 64 81 143 45 222 177 111 62 58 79 31 17 218 61 253 69 170 47 197 169 105 120 41 46 224 92 234 92 145 128 155 186 256 243 208 200 26 48 21 156 248 40 104 178 221 175 196 196 28 249 239 150 49 23 71 114 39 191 196 88 87 234 121 240 123 95 151 130 10 214 34 102 35 193 171 49 112 35 104 207 59 170 136 130 159 16 19 241 125 10 17 129 97 6 127 14 104 118 126 180 225 5 185 225 202 90 230 5 125 99 207 119 39 131 101 93 147 43 21 216 86 35 75 112 64 199 202 30 104 10 185 165 107 95 2 71 25 75 201 28 189 144 155 78 58 228 90 2 100 120 70 172 219 63 168 192 169 134 215 36 17 158 192 1 98 205 137 ^ 522 1 139 130 12 42 22 131 206 33 162 161 186 142 14 211 57 141 39 132 187 80 143 216 85 173 198 109 148 246 67 197 173 192 106 37 217 64 82 56 166 218 4 126 184 227 114 213 228 91 172 221 150 155 187 84 231 204 116 124 5 101 5 97 175 109 144 158 79 201 222 92 149 215 143 214 170 50 165 22 133 121 156 160 248 236 9 183 248 240 62 171 21 156 162 163 101 7 12 40 107 8 208 204 112 36 17 70 89 255 183 252 70 85 167 195 256 154 243 210 115 147 46 108 204 114 209 140 103 176 47 50 163 107 10 123 69 110 123 67 195 69 108 208 202 197 171 19 241 39 130 14 215 145 129 70 83 29 72 67 193 85 169 110 121 152 72 2 205 58 83 33 160 246 63 109 150 161 190 195 2 207 231 206 31 247 38 188 55 222 86 146 69 114 211 55 226 174 134 100 30 18 47 48 25 242 235 36 19 243 212 30 12 44 195 254 239 120 177 28 97 179 162 167 189 253 8 214 172 223 65 20 220 171 23 71 27 161 188 57 137 209 144 156 164 78 224 5 99 90 232 177 22 129 68 168 129 74 136 17 68 174 132 185 165 20 218 256 158 73 198 111 63 111 65 26 188 59 52 74 142 20 214 168 135 42 24 46 106 31 249 176 53 53 51 136 13 15 151 136 11 100 28 103 182 50 161 192 110 125 240 60 256 156 158 75 113 234 96 198 115 151 134 96 200 30 16 132 183 250 155 185 169 108 206 29 74 138 190 191 172 219 235 32 189 255 181 79 205 52 80 145 131 208 206 27 159 15 157 104 122 94 66 253 6 41 49 225 201 5 95 2 209 146 71 29 76 53 55 224 1 11 102 201 3 180 137 211 59 56 162 165 16 130 10 127 157 98 119 241 37 215 149 217 58 79 203 137 215 147 44 193 81 116 122 90 236 7 10 125 242 233 121 154 245 125 238 145 133 123 71 25 246 65 24 50 159 19 245 127 153 45 131 210 121 150 157 102 207 229 33 166 214 174 138 188 53 49 221 148 240 64 86 144 154 249 178 226 176 49 223 63 105 97 173 194 21 160 250 151 132 181 77 32 187 82 58 81 118 37 213 234 94 60 250 153 47 46 110 119 237 207 227 118 43 216 87 88 63 107 12 38 192 108 210 117 62 169 106 33 164 76 51 211 ^ 540 0 101 1 180 50 70 51 143 210 32 181 163 191 81 31 245 123 63 16 135 30 17 154 75 26 93 92 62 163 14 43 129 119 244 144 240 148 70 134 105 91 166 42 27 155 94 28 102 31 79 199 84 225 110 128 89 85 255 9 17 60 259 5 187 74 224 91 83 80 146 238 233 207 138 18 39 39 133 209 230 179 154 252 64 255 175 158 82 50 247 89 2 33 128 100 199 135 41 131 34 107 140 67 200 197 86 140 16 124 176 137 122 178 52 245 174 139 37 41 48 72 226 6 206 119 233 30 100 116 173 160 214 173 26 176 54 160 80 135 124 93 175 24 44 191 164 210 83 257 184 140 99 86 57 54 243 42 16 41 214 256 205 57 188 21 161 99 180 133 32 192 17 71 113 145 219 231 198 199 1 3 12 211 228 4 31 213 237 203 48 249 4 125 72 215 152 66 87 76 56 252 241 33 77 24 178 229 23 76 222 176 220 84 59 186 106 38 103 93 81 165 23 242 146 155 11 66 4 114 175 75 120 169 113 228 181 69 115 60 82 227 25 251 85 172 47 136 186 138 184 223 61 184 191 175 107 6 29 81 114 207 221 197 137 216 254 73 194 192 194 109 232 11 98 107 234 143 221 146 61 195 88 55 139 120 3 189 249 87 87 170 132 13 147 51 132 96 109 149 49 217 233 113 62 257 90 64 78 137 39 216 171 111 53 58 73 28 8 215 58 250 66 170 38 197 169 102 114 41 37 218 86 234 92 145 125 155 177 250 243 208 200 20 48 21 150 245 40 101 178 218 169 196 190 19 246 236 141 46 23 65 108 36 188 187 85 78 231 115 237 120 86 151 130 4 208 34 96 26 187 168 40 112 32 98 201 50 164 127 121 159 7 19 235 122 1 14 126 91 118 5 104 112 126 174 222 259 182 225 193 90 230 2 116 90 198 116 39 122 95 90 147 40 18 216 77 35 75 109 55 190 196 24 95 7 185 159 101 95 256 71 19 69 198 22 180 144 146 72 49 228 87 253 94 111 64 172 213 60 165 189 166 125 206 36 11 149 183 255 92 196 201 133 126 8 38 20 131 200 31 162 161 182 142 14 209 53 141 35 126 185 76 139 214 79 167 198 105 142 242 63 193 173 192 100 33 211 62 80 52 162 212 258 120 180 227 108 213 226 89 168 217 150 151 181 80 229 200 114 124 259 99 3 95 173 109 138 152 77 201 129 ^ 555 0 84 149 215 139 210 158 38 153 14 133 109 152 156 248 232 9 183 240 236 50 167 17 148 158 163 93 3 8 32 103 8 200 204 108 32 9 58 89 247 175 244 66 85 155 191 256 154 239 210 115 139 42 108 200 110 209 132 103 176 39 42 151 99 10 115 65 102 119 63 187 258 69 100 204 202 193 171 15 233 35 118 6 211 141 125 70 83 29 68 67 185 81 157 106 117 148 64 2 193 46 75 33 160 246 55 97 138 153 182 183 260 195 223 198 27 247 38 184 55 222 78 142 57 106 211 47 226 170 126 96 18 6 43 40 25 238 227 28 11 235 212 30 36 195 254 239 116 165 28 85 175 150 167 185 249 258 206 160 215 65 8 220 163 19 63 19 157 180 57 137 201 136 144 160 78 216 259 95 86 232 177 22 129 68 168 117 74 124 13 56 174 124 181 157 12 218 248 158 69 194 103 51 99 53 14 176 59 52 62 130 20 214 156 123 30 20 46 106 23 249 164 45 49 47 132 9 15 139 136 7 100 16 91 182 46 149 184 98 121 240 48 252 156 154 71 109 226 96 186 107 143 134 92 188 22 4 128 179 242 151 173 161 104 202 25 70 126 190 179 168 211 235 24 181 251 173 67 205 40 68 137 127 196 206 23 155 3 145 92 114 82 66 253 256 29 37 221 189 5 91 256 197 138 59 21 72 41 51 224 255 3 102 193 3 176 133 203 51 56 154 165 8 126 2 119 157 86 107 237 33 203 145 217 54 71 203 125 207 143 40 193 77 116 122 78 236 7 6 117 242 225 113 150 241 125 238 133 129 111 67 17 242 57 12 50 147 7 237 127 153 45 123 198 121 146 149 90 199 221 21 166 202 162 130 188 53 45 217 148 232 52 82 140 142 245 166 222 172 41 219 63 93 97 169 194 9 152 250 147 132 177 65 28 179 74 50 73 118 37 201 230 94 60 246 149 47 38 110 115 233 203 219 106 43 208 75 76 59 95 12 30 188 96 206 117 54 165 102 25 164 76 39 136 101 261 178 48 64 45 143 208 32 177 159 189 79 31 245 123 61 10 135 24 13 150 73 24 87 90 62 161 10 41 125 113 244 140 236 144 66 128 105 91 162 36 27 153 88 22 98 27 79 199 84 223 104 128 85 81 251 5 17 54 259 1 187 70 220 89 79 74 144 234 229 205 134 18 37 33 129 205 228 179 148 252 62 255 171 152 82 46 243 83 260 27 122 98 195 129 37 127 28 105 134 207 ^ 545 1 196 193 86 136 16 120 168 133 114 170 48 237 162 135 29 29 40 60 218 2 198 119 229 22 92 108 161 148 202 165 26 164 50 152 80 127 116 85 171 24 44 191 160 198 71 249 180 140 99 82 53 54 235 42 12 37 206 248 193 49 176 9 157 91 180 129 20 188 5 63 109 137 219 231 190 195 1 259 8 207 224 19 201 237 199 36 241 256 117 72 203 152 58 87 64 48 248 241 29 77 20 166 229 11 72 214 172 216 76 55 174 94 34 99 93 73 153 19 238 138 147 263 54 4 102 163 63 120 157 113 220 181 57 111 52 78 223 13 251 73 164 39 132 186 138 184 223 61 172 179 175 107 6 17 81 114 207 213 185 125 212 246 73 190 184 186 101 224 11 98 95 226 131 221 146 49 187 88 51 139 112 255 189 245 75 79 162 124 9 135 51 128 92 97 141 49 213 233 105 54 257 82 64 74 129 31 208 163 111 41 58 65 24 260 211 54 246 62 170 26 197 169 98 106 41 25 210 78 234 92 145 121 155 165 242 243 208 200 12 48 21 142 241 40 97 178 214 161 196 182 7 242 232 129 42 23 57 100 32 184 175 81 66 227 107 233 116 74 151 130 260 200 34 88 14 179 164 28 112 28 90 193 38 156 115 109 159 259 19 227 118 253 10 122 83 256 106 257 104 104 126 166 218 255 178 225 181 90 230 262 104 78 186 112 39 110 87 86 147 36 14 216 65 35 75 105 43 178 188 16 83 3 185 151 93 95 252 71 11 61 194 14 168 144 134 64 37 228 83 245 86 99 56 172 205 56 161 185 162 113 194 36 3 137 171 251 84 184 197 121 118 30 16 131 188 27 162 161 174 142 14 205 45 141 27 114 181 68 131 210 67 155 198 97 130 234 55 185 173 192 88 25 199 58 76 44 154 200 250 108 172 227 96 213 222 85 160 209 150 143 169 72 225 192 110 124 251 95 263 91 169 109 126 140 73 201 204 80 149 215 137 208 152 32 147 10 133 103 150 154 248 230 9 183 236 234 44 165 15 144 156 163 89 1 6 28 101 8 196 204 106 30 5 52 89 243 171 240 64 85 149 189 256 154 237 210 115 135 40 108 198 108 209 128 103 176 35 38 145 95 10 111 63 98 117 61 183 258 69 96 202 202 191 171 13 229 33 112 2 209 139 123 70 83 29 66 67 181 79 151 104 115 146 60 2 187 40 71 33 160 246 51 91 132 178 ^ 563 1 174 171 260 183 215 190 23 247 38 180 55 222 70 138 45 98 211 39 226 166 118 92 6 260 39 32 25 234 219 20 3 227 212 30 254 28 195 254 239 112 153 28 73 171 138 167 181 245 250 198 148 207 65 262 220 155 15 55 11 153 172 57 137 193 128 132 156 78 208 255 91 82 232 177 22 129 68 168 105 74 112 9 44 174 116 177 149 4 218 240 158 65 190 95 39 87 41 2 164 59 52 50 118 20 214 144 111 18 16 46 106 15 249 152 37 45 43 128 5 15 127 136 3 100 4 79 182 42 137 176 86 117 240 36 248 156 150 67 105 218 96 174 99 135 134 88 176 14 258 124 175 234 147 161 153 100 198 21 66 114 190 167 164 203 235 16 173 247 165 55 205 28 56 129 123 184 206 19 151 257 133 80 106 70 66 253 248 17 25 217 177 5 87 252 185 130 47 13 68 29 47 224 251 261 102 185 3 172 129 195 43 56 146 165 122 260 111 157 74 95 233 29 191 141 217 50 63 203 113 199 139 36 193 73 116 122 66 236 7 2 109 242 217 105 146 237 125 238 121 125 99 63 9 238 49 50 135 261 229 127 153 45 115 186 121 142 141 78 191 213 9 166 190 150 122 188 53 41 213 148 224 40 78 136 130 241 154 218 168 33 215 63 81 97 165 194 263 144 250 143 132 173 53 24 171 66 42 65 118 37 189 226 94 60 242 145 47 30 110 111 229 199 211 94 43 200 63 64 55 83 12 22 184 84 202 117 46 161 98 17 164 76 27 132 101 261 174 44 52 33 143 204 32 169 151 185 75 31 245 123 57 264 135 12 5 142 69 20 75 86 62 157 2 37 117 101 244 132 228 136 58 116 105 91 154 24 27 149 76 10 90 19 79 199 84 219 92 128 77 73 243 263 17 42 259 259 187 62 212 85 71 62 140 226 221 201 126 18 33 21 121 197 224 179 136 252 58 255 163 140 82 38 235 71 256 15 110 94 187 117 29 119 16 101 122 49 194 191 86 134 16 118 164 131 110 166 46 233 156 133 25 23 36 54 214 194 119 227 18 88 104 155 142 196 161 26 158 48 148 80 123 112 81 169 24 44 191 158 192 65 245 178 140 99 80 51 54 231 42 10 35 202 244 187 45 170 3 155 87 180 127 14 186 265 59 107 133 219 231 186 193 1 257 6 205 222 264 13 195 237 197 30 237 252 113 72 197 152 54 87 58 44 246 241 27 77 18 160 229 5 70 210 170 214 72 53 168 88 32 97 93 69 261 ^ 563 1 15 234 130 139 255 42 4 90 151 51 120 145 113 212 181 45 107 44 74 219 1 251 61 156 31 128 186 138 184 223 61 160 167 175 107 6 5 81 114 207 205 173 113 208 238 73 186 176 178 93 216 11 98 83 218 119 221 146 37 179 88 47 139 104 247 189 241 63 71 154 116 5 123 51 124 88 85 133 49 209 233 97 46 257 74 64 70 121 23 200 155 111 29 58 57 20 252 207 50 242 58 170 14 197 169 94 98 41 13 202 70 234 92 145 117 155 153 234 243 208 200 4 48 21 134 237 40 93 178 210 153 196 174 263 238 228 117 38 23 49 92 28 180 163 77 54 223 99 229 112 62 151 130 256 192 34 80 2 171 160 16 112 24 82 185 26 148 103 97 159 251 19 219 114 245 6 118 75 252 94 249 104 96 126 158 214 251 174 225 169 90 230 262 92 66 174 108 39 98 79 82 147 32 10 216 53 35 75 101 31 166 180 8 71 267 185 143 85 95 248 71 3 53 190 6 156 144 122 56 25 228 79 237 78 87 48 172 197 52 157 181 158 101 182 36 263 125 159 247 76 172 193 109 110 260 22 12 131 176 23 162 161 166 142 14 201 37 141 19 102 177 60 123 206 55 143 198 89 118 226 47 177 173 192 76 17 187 54 72 36 146 188 242 96 164 227 84 213 218 81 152 201 150 135 157 64 221 184 106 124 243 91 263 87 165 109 114 128 69 201 192 72 149 215 133 204 140 20 135 2 133 91 146 150 248 226 9 183 228 230 32 161 11 136 152 163 81 265 2 20 97 8 188 204 102 26 265 40 89 235 163 232 60 85 137 185 256 154 233 210 115 127 36 108 194 104 209 120 103 176 27 30 133 87 10 103 59 90 113 57 175 258 69 88 198 202 187 171 9 221 29 100 262 205 135 119 70 83 29 62 67 173 75 139 100 111 142 52 2 175 28 63 33 160 246 43 79 120 141 170 165 260 177 211 186 21 247 38 178 55 222 66 136 39 94 211 35 226 164 114 90 256 37 28 25 232 215 16 267 223 212 30 250 24 195 254 239 110 147 28 67 169 132 167 179 243 246 194 142 203 65 258 220 151 13 51 7 151 168 57 137 189 124 126 154 78 204 253 89 80 232 177 22 129 68 168 99 74 106 7 38 174 112 175 145 218 236 158 63 188 91 33 81 35 264 158 59 52 44 112 20 214 138 105 12 14 46 106 11 249 146 33 43 41 126 3 15 121 136 1 100 266 73 182 40 131 172 80 115 240 30 246 186 ^ 573 0 146 63 101 210 96 162 91 127 134 84 164 6 250 120 171 226 143 149 145 96 194 17 62 102 190 155 160 195 235 8 165 243 157 43 205 16 44 121 119 172 206 15 147 249 121 68 98 58 66 253 240 5 13 213 165 5 83 248 173 122 35 5 64 17 43 224 247 257 102 177 3 168 125 187 35 56 138 165 262 118 256 103 157 62 83 229 25 179 137 217 46 55 203 101 191 135 32 193 69 116 122 54 236 7 268 101 242 209 97 142 233 125 238 109 121 87 59 1 234 41 258 50 123 253 221 127 153 45 107 174 121 138 133 66 183 205 267 166 178 138 114 188 53 37 209 148 216 28 74 132 118 237 142 214 164 25 211 63 69 97 161 194 255 136 250 139 132 169 41 20 163 58 34 57 118 37 177 222 94 60 238 141 47 22 110 107 225 195 203 82 43 192 51 52 51 71 12 14 180 72 198 117 38 157 94 9 164 76 15 128 101 261 170 40 40 21 143 200 32 161 143 181 71 31 245 123 53 256 135 267 134 65 16 63 82 62 153 264 33 109 89 244 124 220 128 50 104 105 91 146 12 27 145 64 268 82 11 79 199 84 215 80 128 69 65 235 259 17 30 259 255 187 54 204 81 63 50 136 218 213 197 118 18 29 9 113 189 220 179 124 252 54 255 155 128 82 30 227 59 252 3 98 90 179 105 21 111 4 97 110 37 190 187 86 130 16 114 156 127 102 158 42 225 144 129 17 11 28 42 206 266 186 119 223 10 80 96 143 130 184 153 26 146 44 140 80 115 104 73 165 24 44 191 154 180 53 237 174 140 99 76 47 54 223 42 6 31 194 236 175 37 158 261 151 79 180 123 2 182 257 51 103 125 219 231 178 189 1 253 2 201 218 264 1 183 237 193 18 229 244 105 72 185 152 46 87 46 36 242 241 23 77 14 148 229 263 66 202 166 210 64 49 156 76 28 93 93 61 135 13 232 126 135 251 36 4 84 145 45 120 139 113 208 181 39 105 40 72 217 265 251 55 152 27 126 186 138 184 223 61 154 161 175 107 6 269 81 114 207 201 167 107 206 234 73 184 172 174 89 212 11 98 77 214 113 221 146 31 175 88 45 139 100 243 189 239 57 67 150 112 3 117 51 122 86 79 129 49 207 233 93 42 257 70 64 68 117 19 196 151 111 23 58 53 18 248 205 48 240 56 170 8 197 169 92 94 41 7 198 66 234 92 145 115 155 147 230 243 208 200 48 21 130 235 40 91 178 208 149 196 170 259 236 226 111 36 23 45 88 26 178 157 207 ^ 566 1 42 219 91 225 108 50 151 130 252 184 34 72 262 163 156 4 112 20 74 177 14 140 91 85 159 243 19 211 110 237 2 114 67 248 82 241 104 88 126 150 210 247 170 225 157 90 230 262 80 54 162 104 39 86 71 78 147 28 6 216 41 35 75 97 19 154 172 59 267 185 135 77 95 244 71 267 45 186 270 144 144 110 48 13 228 75 229 70 75 40 172 189 48 153 177 154 89 170 36 259 113 147 243 68 160 189 97 102 256 14 8 131 164 19 162 161 158 142 14 197 29 141 11 90 173 52 115 202 43 131 198 81 106 218 39 169 173 192 64 9 175 50 68 28 138 176 234 84 156 227 72 213 214 77 144 193 150 127 145 56 217 176 102 124 235 87 263 83 161 109 102 116 65 201 180 64 149 215 129 200 128 8 123 266 133 79 142 146 248 222 9 183 220 226 20 157 7 128 148 163 73 265 270 12 93 8 180 204 98 22 261 28 89 227 155 224 56 85 125 181 256 154 229 210 115 119 32 108 190 100 209 112 103 176 19 22 121 79 10 95 55 82 109 53 167 258 69 80 194 202 183 171 5 213 25 88 258 201 131 115 70 83 29 58 67 165 71 127 96 107 138 44 2 163 16 55 33 160 246 35 67 108 133 162 153 260 165 203 178 17 247 38 174 55 222 58 132 27 86 211 27 226 160 106 86 260 248 33 20 25 228 207 8 263 215 212 30 242 16 195 254 239 106 135 28 55 165 120 167 175 239 238 186 130 195 65 250 220 143 9 43 271 147 160 57 137 181 116 114 150 78 196 249 85 76 232 177 22 129 68 168 87 74 94 3 26 174 104 171 137 264 218 228 158 59 184 83 21 69 23 256 146 59 52 32 100 20 214 126 93 10 46 106 3 249 134 25 39 37 122 271 15 109 136 269 100 258 61 182 36 119 164 68 111 240 18 242 156 144 61 99 206 96 156 87 123 134 82 158 2 246 118 169 222 141 143 141 94 192 15 60 96 190 149 158 191 235 4 161 241 153 37 205 10 38 117 117 166 206 13 145 245 115 62 94 52 66 253 236 271 7 211 159 5 81 246 167 118 29 1 62 11 41 224 245 255 102 173 3 166 123 183 31 56 134 165 260 116 254 99 157 56 77 227 23 173 135 217 44 51 203 95 187 133 30 193 67 116 122 48 236 7 268 97 242 205 93 140 231 125 238 103 119 81 57 269 232 37 254 50 117 249 217 127 153 45 103 168 121 136 129 60 179 201 263 166 172 132 110 188 53 35 207 148 212 262 ^ 589 0 70 128 106 233 130 210 160 17 207 63 57 97 157 194 247 128 250 135 132 165 29 16 155 50 26 49 118 37 165 218 94 60 234 137 47 14 110 103 221 191 195 70 43 184 39 40 47 59 12 6 176 60 194 117 30 153 90 1 164 76 3 124 101 261 166 36 28 9 143 196 32 153 135 177 67 31 245 123 49 248 135 262 263 126 61 12 51 78 62 149 260 29 101 77 244 116 212 120 42 92 105 91 138 27 141 52 260 74 3 79 199 84 211 68 128 61 57 227 255 17 18 259 251 187 46 196 77 55 38 132 210 205 193 110 18 25 271 105 181 216 179 112 252 50 255 147 116 82 22 219 47 248 265 86 86 171 93 13 103 266 93 98 25 186 183 86 126 16 110 148 123 94 150 38 217 132 125 9 273 20 30 198 266 178 119 219 2 72 88 131 118 172 145 26 134 40 132 80 107 96 65 161 24 44 191 150 168 41 229 170 140 99 72 43 54 215 42 2 27 186 228 163 29 146 253 147 71 180 119 264 178 249 43 99 117 219 231 170 185 1 249 272 197 214 264 263 171 237 189 6 221 236 97 72 173 152 38 87 34 28 238 241 19 77 10 136 229 255 62 194 162 206 56 45 144 64 24 89 93 53 123 9 228 118 127 243 24 4 72 133 33 120 127 113 200 181 27 101 32 68 213 257 251 43 144 19 122 186 138 184 223 61 142 149 175 107 6 261 81 114 207 193 155 95 202 226 73 180 164 166 81 204 11 98 65 206 101 221 146 19 167 88 41 139 92 235 189 235 45 59 142 104 273 105 51 118 82 67 121 49 203 233 85 34 257 62 64 64 109 11 188 143 111 11 58 45 14 240 201 44 236 52 170 270 197 169 88 86 41 269 190 58 234 92 145 111 155 135 222 243 208 200 266 48 21 122 231 40 87 178 204 141 196 162 251 232 222 99 32 23 37 80 22 174 145 71 36 217 87 223 106 44 151 130 250 180 34 68 258 159 154 272 112 18 70 173 8 136 85 79 159 239 19 207 108 233 112 63 246 76 237 104 84 126 146 208 245 168 225 151 90 230 262 74 48 156 102 39 80 67 76 147 26 4 216 35 35 75 95 13 148 168 270 53 267 185 131 73 95 242 71 265 41 184 268 138 144 104 44 7 228 73 225 66 69 36 172 185 46 151 175 152 83 164 36 257 107 141 241 64 154 187 91 98 254 10 6 131 158 17 162 161 154 142 14 195 25 141 7 84 171 48 111 200 37 125 198 77 100 214 35 165 173 192 58 5 169 48 66 24 134 170 230 78 152 227 66 213 212 75 140 189 150 123 139 52 215 172 124 ^ 584 0 124 227 83 263 79 157 109 90 104 61 201 168 56 149 215 125 196 116 272 111 262 133 67 138 142 248 218 9 183 212 222 8 153 3 120 144 163 65 265 270 4 89 8 172 204 94 18 257 16 89 219 147 216 52 85 113 177 256 154 225 210 115 111 28 108 186 96 209 104 103 176 11 14 109 71 10 87 51 74 105 49 159 258 69 72 190 202 179 171 1 205 21 76 254 197 127 111 70 83 29 54 67 157 67 115 92 103 134 36 2 151 4 47 33 160 246 27 55 96 125 154 141 260 153 195 170 13 247 38 170 55 222 50 128 15 78 211 19 226 156 98 82 252 240 29 12 25 224 199 259 207 212 30 234 8 195 254 239 102 123 28 43 161 108 167 171 235 230 178 118 187 65 242 220 135 5 35 267 143 152 57 137 173 108 102 146 78 188 245 81 72 232 177 22 129 68 168 75 74 82 275 14 174 96 167 129 260 218 220 158 55 180 75 9 57 11 248 134 59 52 20 88 20 214 114 81 264 6 46 106 271 249 122 17 35 33 118 271 15 97 136 269 100 250 49 182 32 107 156 56 107 240 6 238 156 140 57 95 198 96 144 79 115 134 78 146 270 238 114 165 214 137 131 133 90 188 11 56 84 190 137 154 183 235 272 153 237 145 25 205 274 26 109 113 154 206 9 141 237 103 50 86 40 66 253 228 263 271 207 147 5 77 242 155 110 17 269 58 275 37 224 241 251 102 165 3 162 119 175 23 56 126 165 256 112 250 91 157 44 65 223 19 161 131 217 40 43 203 83 179 129 26 193 63 116 122 36 236 7 268 89 242 197 85 136 227 125 238 91 115 69 53 265 228 29 246 50 105 241 209 127 153 45 95 156 121 132 121 48 171 193 255 166 160 120 102 188 53 31 203 148 204 10 68 126 100 231 124 208 158 13 205 63 51 97 155 194 243 124 250 133 132 163 23 14 151 46 22 45 118 37 159 216 94 60 232 135 47 10 110 101 219 189 191 64 43 180 33 34 45 53 12 2 174 54 192 117 26 151 88 273 164 76 273 122 101 261 164 34 22 3 143 194 32 149 131 175 65 31 245 123 47 244 135 258 261 122 59 10 45 76 62 147 258 27 97 71 244 112 208 116 38 86 105 91 134 270 27 139 46 256 70 275 79 199 84 209 62 128 57 53 223 253 17 12 259 249 187 42 192 75 51 32 130 206 201 191 106 18 23 267 101 177 214 179 106 252 48 255 143 110 82 18 215 41 246 261 80 84 167 87 9 99 262 91 92 19 184 181 86 124 16 108 144 121 90 146 36 213 126 123 5 269 230 ^ 587 0 18 190 266 170 119 215 272 64 80 119 106 160 137 26 122 36 124 80 99 88 57 157 24 44 191 146 156 29 221 166 140 99 68 39 54 207 42 276 23 178 220 151 21 134 245 143 63 180 115 256 174 241 35 95 109 219 231 162 181 1 245 272 193 210 264 255 159 237 185 272 213 228 89 72 161 152 30 87 22 20 234 241 15 77 6 124 229 247 58 186 158 202 48 41 132 52 20 85 93 45 111 5 224 110 119 235 12 4 60 121 21 120 115 113 192 181 15 97 24 64 209 249 251 31 136 11 118 186 138 184 223 61 130 137 175 107 6 253 81 114 207 185 143 83 198 218 73 176 156 158 73 196 11 98 53 198 89 221 146 7 159 88 37 139 84 227 189 231 33 51 134 96 273 93 51 114 78 55 113 49 199 233 77 26 257 54 64 60 101 3 180 135 111 277 58 37 10 232 197 40 232 48 170 262 197 169 84 78 41 261 182 50 234 92 145 107 155 123 214 243 208 200 262 48 21 114 227 40 83 178 200 133 196 154 243 228 218 87 28 23 29 72 18 170 133 67 24 213 79 219 102 32 151 130 246 172 34 60 250 151 150 264 112 14 62 165 274 128 73 67 159 231 19 199 104 225 274 108 55 242 64 229 104 76 126 138 204 241 164 225 139 90 230 262 62 36 144 98 39 68 59 72 147 22 216 23 35 75 91 1 136 160 266 41 267 185 123 65 95 238 71 261 33 180 264 126 144 92 36 273 228 69 217 58 57 28 172 177 42 147 171 148 71 152 36 253 95 129 237 56 142 183 79 90 250 2 2 131 146 13 162 161 146 142 14 191 17 141 277 72 167 40 103 196 25 113 198 69 88 206 27 157 173 192 46 275 157 44 62 16 126 158 222 66 144 227 54 213 208 71 132 181 150 115 127 44 211 164 96 124 223 81 263 77 155 109 84 98 59 201 162 52 149 215 123 194 110 268 105 260 133 61 136 140 248 216 9 183 208 220 2 151 1 116 142 163 61 265 270 87 8 168 204 92 16 255 10 89 215 143 212 50 85 107 175 256 154 223 210 115 107 26 108 184 94 209 100 103 176 7 10 103 67 10 83 49 70 103 47 155 258 69 68 188 202 177 171 277 201 19 70 252 195 125 109 70 83 29 52 67 153 65 109 90 101 132 32 2 145 276 43 33 160 246 23 49 90 121 150 135 260 147 191 166 11 247 38 168 55 222 46 126 9 74 211 15 226 154 94 80 248 236 27 8 25 222 195 274 257 203 212 30 230 4 195 254 239 100 117 28 37 159 102 167 169 233 226 174 112 183 65 238 220 131 3 31 270 ^ 609 1 140 146 57 137 167 102 93 143 78 182 242 78 69 232 177 22 129 68 168 66 74 73 275 5 174 90 164 123 257 218 214 158 52 177 69 48 2 242 125 59 52 11 79 20 214 105 72 258 3 46 106 268 249 113 11 32 30 115 271 15 88 136 269 100 244 40 182 29 98 150 47 104 240 276 235 156 137 54 92 192 96 135 73 109 134 75 137 267 232 111 162 208 134 122 127 87 185 8 53 75 190 128 151 177 235 269 147 234 139 16 205 268 17 103 110 145 206 6 138 231 94 41 80 31 66 253 222 257 265 204 138 5 74 239 146 104 8 266 55 269 34 224 238 248 102 159 3 159 116 169 17 56 120 165 253 109 247 85 157 35 56 220 16 152 128 217 37 37 203 74 173 126 23 193 60 116 122 27 236 7 268 83 242 191 79 133 224 125 238 82 112 60 50 262 225 23 240 50 96 235 203 127 153 45 89 147 121 129 115 39 165 187 249 166 151 111 96 188 53 28 200 148 198 1 65 123 91 228 115 205 155 7 202 63 42 97 152 194 237 118 250 130 132 160 14 11 145 40 16 39 118 37 150 213 94 60 229 132 47 4 110 98 216 186 185 55 43 174 24 25 42 44 12 275 171 45 189 117 20 148 85 270 164 76 267 119 101 261 161 31 13 273 143 191 32 143 125 172 62 31 245 123 44 238 135 252 258 116 56 7 36 73 62 144 255 24 91 62 244 106 202 110 32 77 105 91 128 264 27 136 37 250 64 272 79 199 84 206 53 128 51 47 217 250 17 3 259 246 187 36 186 72 45 23 127 200 195 188 100 18 20 261 95 171 211 179 97 252 45 255 137 101 82 12 209 32 243 255 71 81 161 78 3 93 256 88 83 10 181 178 86 121 16 105 138 118 84 140 33 207 117 120 278 263 10 15 188 266 168 119 214 271 62 78 116 103 157 135 26 119 35 122 80 97 86 55 156 24 44 191 145 153 26 219 165 140 99 67 38 54 205 42 276 22 176 218 148 19 131 243 142 61 180 114 254 173 239 33 94 107 219 231 160 180 1 244 272 192 209 264 253 156 237 184 270 211 226 87 72 158 152 28 87 19 18 233 241 14 77 5 121 229 245 57 184 157 201 46 40 129 49 19 84 93 43 108 4 223 108 117 233 9 4 57 118 18 120 112 113 190 181 12 96 22 63 208 247 251 28 134 9 117 186 138 184 223 61 127 134 175 107 6 251 81 114 207 183 140 80 197 216 73 175 154 156 71 194 11 98 50 196 86 221 146 4 157 88 36 139 82 225 189 230 30 49 132 94 273 90 51 113 77 52 111 49 198 233 75 24 257 52 64 59 99 1 178 133 111 275 58 35 9 230 196 39 231 47 170 216 ^ 589 0 197 169 81 72 41 255 176 44 234 92 145 104 155 114 208 243 208 200 259 48 21 108 224 40 80 178 197 127 196 148 237 225 215 78 25 23 23 66 15 167 124 64 15 210 73 216 99 23 151 130 243 166 34 54 244 145 147 258 112 11 56 159 268 122 64 58 159 225 19 193 101 219 274 105 49 239 55 223 104 70 126 132 201 238 161 225 130 90 230 262 53 27 135 95 39 59 53 69 147 19 278 216 14 35 75 88 273 127 154 263 32 267 185 117 59 95 235 71 258 27 177 261 117 144 83 30 267 228 66 211 52 48 22 172 171 39 144 168 145 62 143 36 250 86 120 234 50 133 180 70 84 247 277 280 131 137 10 162 161 140 142 14 188 11 141 274 63 164 34 97 193 16 104 198 63 79 200 21 151 173 192 37 272 148 41 59 10 120 149 216 57 138 227 45 213 205 68 126 175 150 109 118 38 208 158 93 124 217 78 263 74 152 109 75 89 56 201 153 46 149 215 120 191 101 262 96 257 133 52 133 137 248 213 9 183 202 217 274 148 279 110 139 163 55 265 270 275 84 8 162 204 89 13 252 1 89 209 137 206 47 85 98 172 256 154 220 210 115 101 23 108 181 91 209 94 103 176 1 4 94 61 10 77 46 64 100 44 149 258 69 62 185 202 174 171 277 195 16 61 249 192 122 106 70 83 29 49 67 147 62 100 87 98 129 26 2 136 270 37 33 160 246 17 40 81 115 144 126 260 138 185 160 8 247 38 165 55 222 40 123 68 211 9 226 151 88 77 242 230 24 2 25 219 189 271 254 197 212 30 224 279 195 254 239 97 108 28 28 156 93 167 166 230 220 168 103 177 65 232 220 125 25 262 138 142 57 137 163 98 87 141 78 178 240 76 67 232 177 22 129 68 168 60 74 67 275 280 174 86 162 119 255 218 210 158 50 175 65 275 42 277 238 119 59 52 5 73 20 214 99 66 254 1 46 106 266 249 107 7 30 28 113 271 15 82 136 269 100 240 34 182 27 92 146 41 102 240 272 233 156 135 52 90 188 96 129 69 105 134 73 131 265 228 109 160 204 132 116 123 85 183 6 51 69 190 122 149 173 235 267 143 232 135 10 205 264 11 99 108 139 206 4 136 227 88 35 76 25 66 253 218 253 261 202 132 5 72 237 140 100 2 264 53 265 32 224 236 246 102 155 3 157 114 165 13 56 116 165 251 107 245 81 157 29 50 218 14 146 126 217 35 33 203 68 169 124 21 193 58 116 122 21 236 7 268 79 242 187 75 131 222 125 238 76 110 54 48 260 223 19 236 50 90 231 199 127 153 45 270 ^ 623 1 135 121 125 107 27 157 179 241 166 139 99 88 188 53 24 196 148 190 272 61 119 79 224 103 201 151 282 198 63 30 97 148 194 229 110 250 126 132 156 2 7 137 32 8 31 118 37 138 209 94 60 225 128 47 279 110 94 212 182 177 43 43 166 12 13 38 32 12 271 167 33 185 117 12 144 81 266 164 76 259 115 101 261 157 27 1 265 143 187 32 135 117 168 58 31 245 123 40 230 135 244 254 108 52 3 24 69 62 140 251 20 83 50 244 98 194 102 24 65 105 91 120 256 27 132 25 242 56 268 79 199 84 202 41 128 43 39 209 246 17 274 259 242 187 28 178 68 37 11 123 192 187 184 92 18 16 253 87 163 207 179 85 252 41 255 129 89 82 4 201 20 239 247 59 77 153 66 278 85 248 84 71 281 177 174 86 117 16 101 130 114 76 132 29 199 105 116 274 255 2 3 180 266 160 119 210 267 54 70 104 91 145 127 26 107 31 114 80 89 78 47 152 24 44 191 141 141 14 211 161 140 99 63 34 54 197 42 276 18 168 210 136 11 119 235 138 53 180 110 246 169 231 25 90 99 219 231 152 176 1 240 272 188 205 264 245 144 237 180 262 203 218 79 72 146 152 20 87 7 10 229 241 10 77 1 109 229 237 53 176 153 197 38 36 117 37 15 80 93 35 96 219 100 109 225 280 4 45 106 6 120 100 113 182 181 92 14 59 204 239 251 16 126 1 113 186 138 184 223 61 115 122 175 107 6 243 81 114 207 175 128 68 193 208 73 171 146 148 63 186 11 98 38 188 74 221 146 275 149 88 32 139 74 217 189 226 18 41 124 86 273 78 51 109 73 40 103 49 194 233 67 16 257 44 64 55 91 276 170 125 111 267 58 27 5 222 192 35 227 43 170 252 197 169 79 68 41 251 172 40 234 92 145 102 155 108 204 243 208 200 257 48 21 104 222 40 78 178 195 123 196 144 233 223 213 72 23 23 19 62 13 165 118 62 9 208 69 214 97 17 151 130 241 162 34 50 240 141 145 254 112 9 52 155 264 118 58 52 159 221 19 189 99 215 274 103 45 237 49 219 104 66 126 128 199 236 159 225 124 90 230 262 47 21 129 93 39 53 49 67 147 17 278 216 8 35 75 86 269 121 150 261 26 267 185 113 55 95 233 71 256 23 175 259 111 144 77 26 263 228 64 207 48 42 18 172 167 37 142 166 143 56 137 36 248 80 114 232 46 127 178 64 80 245 275 280 131 131 8 162 161 136 142 14 186 7 141 272 57 162 30 93 191 10 98 198 59 73 196 17 147 173 192 31 270 142 39 57 6 116 143 212 51 134 227 39 213 203 66 122 171 150 105 112 34 206 154 91 124 213 76 263 72 150 109 69 83 54 201 147 42 149 202 ^ 602 1 116 187 89 254 84 253 133 40 129 133 248 209 9 183 194 213 266 144 279 102 135 163 47 265 270 271 80 8 154 204 85 9 248 274 89 201 129 198 43 85 86 168 256 154 216 210 115 93 19 108 177 87 209 86 103 176 278 281 82 53 10 69 42 56 96 40 141 258 69 54 181 202 170 171 277 187 12 49 245 188 118 102 70 83 29 45 67 139 58 88 83 94 125 18 2 124 262 29 33 160 246 9 28 69 107 136 114 260 126 177 152 4 247 38 161 55 222 32 119 273 60 211 1 226 147 80 73 234 222 20 279 25 215 181 267 250 189 212 30 216 275 195 254 239 93 96 28 16 152 81 167 162 226 212 160 91 169 65 224 220 117 281 17 258 134 134 57 137 155 90 75 137 78 170 236 72 63 232 177 22 129 68 168 48 74 55 275 272 174 78 158 111 251 218 202 158 46 171 57 267 30 269 230 107 59 52 278 61 20 214 87 54 246 282 46 106 262 249 95 284 26 24 109 271 15 70 136 269 100 232 22 182 23 80 138 29 98 240 264 229 156 131 48 86 180 96 117 61 97 134 69 119 261 220 105 156 196 128 104 115 81 179 2 47 57 190 110 145 165 235 263 135 228 127 283 205 256 284 91 104 127 206 132 219 76 23 68 13 66 253 210 245 253 198 120 5 68 233 128 92 275 260 49 257 28 224 232 242 102 147 3 153 110 157 5 56 108 165 247 103 241 73 157 17 38 214 10 134 122 217 31 25 203 56 161 120 17 193 54 116 122 9 236 7 268 71 242 179 67 127 218 125 238 64 106 42 44 256 219 11 228 50 78 223 191 127 153 45 77 129 121 123 103 21 153 175 237 166 133 93 84 188 53 22 194 148 186 268 59 117 73 222 97 199 149 280 196 63 24 97 146 194 225 106 250 124 132 154 281 5 133 28 4 27 118 37 132 207 94 60 223 126 47 277 110 92 210 180 173 37 43 162 6 7 36 26 12 269 165 27 183 117 8 142 79 264 164 76 255 113 101 261 155 25 280 261 143 185 32 131 113 166 56 31 245 123 38 226 135 240 252 104 50 1 18 67 62 138 249 18 79 44 244 94 190 98 20 59 105 91 116 252 27 130 19 238 52 266 79 199 84 200 35 128 39 35 205 244 17 270 259 240 187 24 174 66 33 5 121 188 183 182 88 18 14 249 83 159 205 179 79 252 39 255 125 83 82 197 14 237 243 53 75 149 60 276 81 244 82 65 277 175 172 86 115 16 99 126 112 72 128 27 195 99 114 272 251 283 282 176 266 156 119 208 265 50 66 98 85 139 123 26 101 29 110 80 85 74 43 150 24 44 191 139 135 8 207 159 140 99 61 248 ^ 609 1 54 189 42 276 14 160 202 124 3 107 227 134 45 180 106 238 165 223 17 86 91 219 231 144 172 1 236 272 184 201 264 237 132 237 176 254 195 210 71 72 134 152 12 87 282 2 225 241 6 77 284 97 229 229 49 168 149 193 30 32 105 25 11 76 93 27 84 283 215 92 101 217 272 4 33 94 281 120 88 113 174 181 275 88 6 55 200 231 251 4 118 280 109 186 138 184 223 61 103 110 175 107 6 235 81 114 207 167 116 56 189 200 73 167 138 140 55 178 11 98 26 180 62 221 146 267 141 88 28 139 66 209 189 222 6 33 116 78 273 66 51 105 69 28 95 49 190 233 59 8 257 36 64 51 83 272 162 117 111 259 58 19 1 214 188 31 223 39 170 244 197 169 75 60 41 243 164 32 234 92 145 98 155 96 196 243 208 200 253 48 21 96 218 40 74 178 191 115 196 136 225 219 209 60 19 23 11 54 9 161 106 58 284 204 61 210 93 5 151 130 237 154 34 42 232 133 141 246 112 5 44 147 256 110 46 40 159 213 19 181 95 207 274 99 37 233 37 211 104 58 126 120 195 232 155 225 112 90 230 262 35 9 117 89 39 41 41 63 147 13 278 216 283 35 75 82 261 109 142 257 14 267 185 105 47 95 229 71 252 15 171 255 99 144 65 18 255 228 60 199 40 30 10 172 159 33 138 162 139 44 125 36 244 68 102 228 38 115 174 52 72 241 271 280 131 119 4 162 161 128 142 14 182 286 141 268 45 158 22 85 187 285 86 198 51 61 188 9 139 173 192 19 266 130 35 53 285 108 131 204 39 126 227 27 213 199 62 114 163 150 97 100 26 202 146 87 124 205 72 263 68 146 109 57 71 50 201 135 34 149 215 114 185 83 250 78 251 133 34 127 131 248 207 9 183 190 211 262 142 279 98 133 163 43 265 270 269 78 8 150 204 83 7 246 270 89 197 125 194 41 85 80 166 256 154 214 210 115 89 17 108 175 85 209 82 103 176 276 279 76 49 10 65 40 52 94 38 137 258 69 50 179 202 168 171 277 183 10 43 243 186 116 100 70 83 29 43 67 135 56 82 81 92 123 14 2 118 258 25 33 160 246 5 22 63 103 132 108 260 120 173 148 2 247 38 159 55 222 28 117 269 56 211 284 226 145 76 71 230 218 18 277 25 213 177 265 248 185 212 30 212 273 195 254 239 91 90 28 10 150 75 167 160 224 208 156 85 165 65 220 220 113 281 13 256 132 130 57 137 151 86 69 135 78 166 234 70 61 232 177 22 129 68 168 42 74 49 275 268 174 74 156 107 249 218 198 158 44 169 53 263 24 265 226 101 59 52 274 55 20 214 81 48 242 282 46 106 260 145 ^ 614 1 83 280 22 20 105 271 15 58 136 269 100 224 10 182 19 68 130 17 94 240 256 225 156 127 44 82 172 96 105 53 89 134 65 107 257 212 101 152 188 124 92 107 77 175 287 43 45 190 98 141 157 235 259 127 224 119 275 205 248 276 83 100 115 206 285 128 211 64 11 60 1 66 253 202 237 245 194 108 5 64 229 116 84 267 256 45 249 24 224 228 238 102 139 3 149 106 149 286 56 100 165 243 99 237 65 157 5 26 210 6 122 118 217 27 17 203 44 153 116 13 193 50 116 122 286 236 7 268 63 242 171 59 123 214 125 238 52 102 30 40 252 215 3 220 50 66 215 183 127 153 45 69 117 121 119 95 9 145 167 229 166 121 81 76 188 53 18 190 148 178 260 55 113 61 218 85 195 145 276 192 63 12 97 142 194 217 98 250 120 132 150 273 1 125 20 285 19 118 37 120 203 94 60 219 122 47 273 110 88 206 176 165 25 43 154 283 284 32 14 12 265 161 15 179 117 138 75 260 164 76 247 109 101 261 151 21 272 253 143 181 32 123 105 162 52 31 245 123 34 218 135 232 248 96 46 286 6 63 62 134 245 14 71 32 244 86 182 90 12 47 105 91 108 244 27 126 7 230 44 262 79 199 84 196 23 128 31 27 197 240 17 262 259 236 187 16 166 62 25 282 117 180 175 178 80 18 10 241 75 151 201 179 67 252 35 255 117 71 82 281 189 2 233 235 41 71 141 48 272 73 236 78 53 269 171 168 86 111 16 95 118 108 64 120 23 187 87 110 268 243 279 274 168 266 148 119 204 261 42 58 86 73 127 115 26 89 25 102 80 77 66 35 146 24 44 191 135 123 285 199 155 140 99 57 28 54 185 42 276 12 156 198 118 288 101 223 132 41 180 104 234 163 219 13 84 87 219 231 140 170 1 234 272 182 199 264 233 126 237 174 250 191 206 67 72 128 152 8 87 278 287 223 241 4 77 284 91 229 225 47 164 147 191 26 30 99 19 9 74 93 23 78 283 213 88 97 213 268 4 27 88 277 120 82 113 170 181 271 86 2 53 198 227 251 287 114 278 107 186 138 184 223 61 97 104 175 107 6 231 81 114 207 163 110 50 187 196 73 165 134 136 51 174 11 98 20 176 56 221 146 263 137 88 26 139 62 205 189 220 29 112 74 273 60 51 103 67 22 91 49 188 233 55 4 257 32 64 49 79 270 158 113 111 255 58 15 288 210 186 29 221 37 170 240 197 169 73 56 41 239 160 28 234 92 145 96 155 90 192 243 208 200 251 48 21 92 216 40 72 178 189 111 196 132 221 217 207 54 17 23 7 50 7 159 100 56 280 202 57 208 91 288 151 130 235 150 34 38 228 129 139 242 112 226 ^ 619 0 38 141 250 104 37 31 159 207 19 175 92 201 274 96 31 230 28 205 104 52 126 114 192 229 152 225 103 90 230 262 26 108 86 39 32 35 60 147 10 278 216 277 35 75 79 255 100 136 254 5 267 185 99 41 95 226 71 249 9 168 252 90 144 56 12 249 228 57 193 34 21 4 172 153 30 135 159 136 35 116 36 241 59 93 225 32 106 171 43 66 238 268 280 131 110 1 162 161 122 142 14 179 283 141 265 36 155 16 79 184 279 77 198 45 52 182 3 133 173 192 10 263 121 32 50 282 102 122 198 30 120 227 18 213 196 59 108 157 150 91 91 20 199 140 84 124 199 69 263 65 143 109 48 62 47 201 126 28 149 215 111 182 74 244 69 248 133 25 124 128 248 204 9 183 184 208 256 139 279 92 130 163 37 265 270 266 75 8 144 204 80 4 243 264 89 191 119 188 38 85 71 163 256 154 211 210 115 83 14 108 172 82 209 76 103 176 273 276 67 43 10 59 37 46 91 35 131 258 69 44 176 202 165 171 277 177 7 34 240 183 113 97 70 83 29 40 67 129 53 73 78 89 120 8 2 109 252 19 33 160 246 289 13 54 97 126 99 260 111 167 142 289 247 38 156 55 222 22 114 263 50 211 281 226 142 70 68 224 212 15 274 25 210 171 262 245 179 212 30 206 270 195 254 239 88 81 28 1 147 66 167 157 221 202 150 76 159 65 214 220 107 281 7 253 129 124 57 137 145 80 60 132 78 160 231 67 58 232 177 22 129 68 168 33 74 40 275 262 174 68 153 101 246 218 192 158 41 166 47 257 15 259 220 92 59 52 268 46 20 214 72 39 236 282 46 106 257 249 80 279 21 19 104 271 15 55 136 269 100 222 7 182 18 65 128 14 93 240 254 224 156 126 43 81 170 96 102 51 87 134 64 104 256 210 100 151 186 123 89 105 76 174 287 42 42 190 95 140 155 235 258 125 223 117 273 205 246 274 81 99 112 206 285 127 209 61 8 58 288 66 253 200 235 243 193 105 5 63 228 113 82 265 255 44 247 23 224 227 237 102 137 3 148 105 147 285 56 98 165 242 98 236 63 157 2 23 209 5 119 117 217 26 15 203 41 151 115 12 193 49 116 122 284 236 7 268 61 242 169 57 122 213 125 238 49 101 27 39 251 214 1 218 50 63 213 181 127 153 45 67 114 121 118 93 6 143 165 227 166 118 78 74 188 53 17 189 148 176 258 54 112 58 217 82 194 144 275 191 63 9 97 141 194 215 96 250 119 132 149 271 123 18 284 17 118 37 117 202 94 60 218 121 47 272 110 87 205 175 163 22 43 152 281 282 31 11 12 264 160 12 178 117 288 137 74 259 164 76 245 108 101 261 150 20 270 251 143 180 264 ^ 639 0 117 99 159 49 31 245 123 31 212 135 226 245 90 43 286 289 60 62 131 242 11 65 23 244 80 176 84 6 38 105 91 102 238 27 123 290 224 38 259 79 199 84 193 14 128 25 21 191 237 17 256 259 233 187 10 160 59 19 276 114 174 169 175 74 18 7 235 69 145 198 179 58 252 32 255 111 62 82 278 183 285 230 229 32 68 135 39 269 67 230 75 44 263 168 165 86 108 16 92 112 105 58 114 20 181 78 107 265 237 276 268 162 266 142 119 201 258 36 52 77 64 118 109 26 80 22 96 80 71 60 29 143 24 44 191 132 114 279 193 152 140 99 54 25 54 179 42 276 9 150 192 109 285 92 217 129 35 180 101 228 160 213 7 81 81 219 231 134 167 1 231 272 179 196 264 227 117 237 171 244 185 200 61 72 119 152 2 87 272 284 220 241 1 77 284 82 229 219 44 158 144 188 20 27 90 10 6 71 93 17 69 283 210 82 91 207 262 4 18 79 271 120 73 113 164 181 265 83 288 50 195 221 251 281 108 275 104 186 138 184 223 61 88 95 175 107 6 225 81 114 207 157 101 41 184 190 73 162 128 130 45 168 11 98 11 170 47 221 146 257 131 88 23 139 56 199 189 217 283 23 106 68 273 51 51 100 64 13 85 49 185 233 49 290 257 26 64 46 73 267 152 107 111 249 58 9 288 204 183 26 218 34 170 234 197 169 70 50 41 233 154 22 234 92 145 93 155 81 186 243 208 200 248 48 21 86 213 40 69 178 186 105 196 126 215 214 204 45 14 23 1 44 4 156 91 53 274 199 51 205 88 282 151 130 232 144 34 32 222 123 136 236 112 34 137 246 100 31 25 159 203 19 171 90 197 274 94 27 228 22 201 104 48 126 110 190 227 150 225 97 90 230 262 20 286 102 84 39 26 31 58 147 8 278 216 273 35 75 77 251 94 132 252 291 267 185 95 37 95 224 71 247 5 166 250 84 144 50 8 245 228 55 189 30 15 172 149 28 133 157 134 29 110 36 239 53 87 223 28 100 169 37 62 236 266 280 131 104 291 162 161 118 142 14 177 281 141 263 30 153 12 75 182 275 71 198 41 46 178 291 129 173 192 4 261 115 30 48 280 98 116 194 24 116 227 12 213 194 57 104 153 150 87 85 16 197 136 82 124 195 67 263 63 141 109 42 56 45 201 120 24 149 215 109 180 68 240 63 246 133 19 122 126 248 202 9 183 180 206 252 137 279 88 128 163 33 265 270 264 73 8 140 204 78 2 241 260 89 187 115 184 36 85 65 161 256 154 209 210 115 79 12 108 170 80 209 72 103 176 271 274 61 39 10 55 35 42 89 33 127 258 69 40 174 202 163 171 277 173 5 28 238 181 111 95 70 83 29 38 67 125 51 67 76 87 118 4 2 103 248 15 33 160 246 287 7 48 93 283 ^ 611 0 87 260 99 159 134 289 247 38 152 55 222 14 110 255 42 211 277 226 138 62 64 216 204 11 270 25 206 163 258 241 171 212 30 198 266 195 254 239 84 69 28 283 143 54 167 153 217 194 142 64 151 65 206 220 99 281 293 249 125 116 57 137 137 72 48 128 78 152 227 63 54 232 177 22 129 68 168 21 74 28 275 254 174 60 149 93 242 218 184 158 37 162 39 249 3 251 212 80 59 52 260 34 20 214 60 27 228 282 46 106 253 249 68 275 17 15 100 271 15 43 136 269 100 214 289 182 14 53 120 2 89 240 246 220 156 122 39 77 162 96 90 43 79 134 60 92 252 202 96 147 178 119 77 97 72 170 287 38 30 190 83 136 147 235 254 117 219 109 265 205 238 266 73 95 100 206 285 123 201 49 290 50 280 66 253 192 227 235 189 93 5 59 224 101 74 257 251 40 239 19 224 223 233 102 129 3 144 101 139 281 56 90 165 238 94 232 55 157 284 11 205 1 107 113 217 22 7 203 29 143 111 8 193 45 116 122 276 236 7 268 53 242 161 49 118 209 125 238 37 97 15 35 247 210 287 210 50 51 205 173 127 153 45 59 102 121 114 85 288 135 157 219 166 106 66 66 188 53 13 185 148 168 250 50 108 46 213 70 190 140 271 187 63 291 97 137 194 207 88 250 115 132 145 263 290 115 10 280 9 118 37 105 198 94 60 214 117 47 268 110 83 201 171 155 10 43 144 273 274 27 293 12 260 156 174 117 284 133 70 255 164 76 237 104 101 261 146 16 262 243 143 176 32 113 95 157 47 31 245 123 29 208 135 222 243 86 41 286 285 58 62 129 240 9 61 17 244 76 172 80 2 32 105 91 98 234 27 121 286 220 34 257 79 199 84 191 8 128 21 17 187 235 17 252 259 231 187 6 156 57 15 272 112 170 165 173 70 18 5 231 65 141 196 179 52 252 30 255 107 56 82 276 179 281 228 225 26 66 131 33 267 63 226 73 38 259 166 163 86 106 16 90 108 103 54 110 18 177 72 105 263 233 274 264 158 266 138 119 199 256 32 48 71 58 112 105 26 74 20 92 80 67 56 25 141 24 44 191 130 108 275 189 150 140 99 52 23 54 175 42 276 7 146 188 103 283 86 213 127 31 180 99 224 158 209 3 79 77 219 231 130 165 1 229 272 177 194 264 223 111 237 169 240 181 196 57 72 113 152 292 87 268 282 218 241 293 77 284 76 229 215 42 154 142 186 16 25 84 4 4 69 93 13 63 283 208 78 87 203 258 4 12 73 267 120 67 113 160 181 261 81 286 48 193 217 251 277 104 273 102 186 138 184 223 61 82 89 175 107 6 221 81 114 207 153 95 35 182 186 73 275 ^ 634 0 120 122 37 160 11 98 295 162 35 221 146 249 123 88 19 139 48 191 189 213 275 15 98 60 273 39 51 96 60 1 77 49 181 233 41 286 257 18 64 42 65 263 144 99 111 241 58 1 288 196 179 22 214 30 170 226 197 169 66 42 41 225 146 14 234 92 145 89 155 69 178 243 208 200 244 48 21 78 209 40 65 178 182 97 196 118 207 210 200 33 10 23 289 36 152 79 49 266 195 43 201 84 274 151 130 228 136 34 24 214 115 132 228 112 292 26 129 238 92 19 13 159 195 19 163 86 189 274 90 19 224 10 193 104 40 126 102 186 223 146 225 85 90 230 262 8 278 90 80 39 14 23 54 147 4 278 216 265 35 75 73 243 82 124 248 283 267 185 87 29 95 220 71 243 293 162 246 72 144 38 237 228 51 181 22 3 288 172 141 24 129 153 130 17 98 36 235 41 75 219 20 88 165 25 54 232 262 280 131 92 291 162 161 110 142 14 173 277 141 259 18 149 4 67 178 267 59 198 33 34 170 287 121 173 192 288 257 103 26 44 276 90 104 186 12 108 227 213 190 53 96 145 150 79 73 8 193 128 78 124 187 63 263 59 137 109 30 44 41 201 108 16 149 215 105 176 56 232 51 242 133 7 118 122 248 198 9 183 172 202 244 133 279 80 124 163 25 265 270 260 69 8 132 204 74 294 237 252 89 179 107 176 32 85 53 157 256 154 205 210 115 71 8 108 166 76 209 64 103 176 267 270 49 31 10 47 31 34 85 29 119 258 69 32 170 202 159 171 277 165 1 16 234 177 107 91 70 83 29 34 67 117 47 55 72 83 114 292 2 91 240 7 33 160 246 283 291 36 85 114 81 260 93 155 130 289 247 38 150 55 222 10 108 251 38 211 275 226 136 58 62 212 200 9 268 25 204 159 256 239 167 212 30 194 264 195 254 239 82 63 28 279 141 48 167 151 215 190 138 58 147 65 202 220 95 281 291 247 123 112 57 137 133 68 42 126 78 148 225 61 52 232 177 22 129 68 168 15 74 22 275 250 174 56 147 89 240 218 180 158 35 160 35 245 293 247 208 74 59 52 256 28 20 214 54 21 224 282 46 106 251 249 62 273 15 13 98 271 15 37 136 269 100 210 285 182 12 47 116 292 87 240 242 218 156 120 37 75 158 96 84 39 75 134 58 86 250 198 94 145 174 117 71 93 70 168 287 36 24 190 77 134 143 235 252 113 217 105 261 205 234 262 69 93 94 206 285 121 197 43 286 46 276 66 253 188 223 231 187 87 5 57 222 95 70 253 249 38 235 17 224 221 231 102 125 3 142 99 135 279 56 86 165 236 92 230 51 157 280 5 203 295 101 111 217 20 3 203 23 139 109 6 193 43 116 122 272 236 7 268 49 242 157 45 116 207 125 238 31 95 9 33 245 220 ^ 638 0 284 204 50 42 199 167 127 153 45 53 93 121 111 79 282 129 151 213 166 97 57 60 188 53 10 182 148 162 244 47 105 37 210 61 187 137 268 184 63 285 97 134 194 201 82 250 112 132 142 257 290 109 4 277 3 118 37 96 195 94 60 211 114 47 265 110 80 198 168 149 1 43 138 267 268 24 287 12 257 153 288 171 117 281 130 67 252 164 76 231 101 101 261 143 13 256 237 143 173 32 107 89 154 44 31 245 123 26 202 135 216 240 80 38 286 279 55 62 126 237 6 55 8 244 70 166 74 293 23 105 91 92 228 27 118 280 214 28 254 79 199 84 188 296 128 15 11 181 232 17 246 259 228 187 150 54 9 266 109 164 159 170 64 18 2 225 59 135 193 179 43 252 27 255 101 47 82 273 173 275 225 219 17 63 125 24 264 57 220 70 29 253 163 160 86 103 16 87 102 100 48 104 15 171 63 102 260 227 271 258 152 266 132 119 196 253 26 42 62 49 103 99 26 65 17 86 80 61 50 19 138 24 44 191 127 99 269 183 147 140 99 49 20 54 169 42 276 4 140 182 94 280 77 207 124 25 180 96 218 155 203 294 76 71 219 231 124 162 1 226 272 174 191 264 217 102 237 166 234 175 190 51 72 104 152 289 87 262 279 215 241 293 77 284 67 229 209 39 148 139 183 10 22 75 292 1 66 93 7 54 283 205 72 81 197 252 4 3 64 261 120 58 113 154 181 255 78 283 45 190 211 251 271 98 270 99 186 138 184 223 61 73 80 175 107 6 215 81 114 207 147 86 26 179 180 73 157 118 120 35 158 11 98 293 160 32 221 146 247 121 88 18 139 46 189 189 212 273 13 96 58 273 36 51 95 59 295 75 49 180 233 39 285 257 16 64 41 63 262 142 97 111 239 58 296 288 194 178 21 213 29 170 224 197 169 65 40 41 223 144 12 234 92 145 88 155 66 176 243 208 200 243 48 21 76 208 40 64 178 181 95 196 116 205 209 199 30 9 23 288 34 296 151 76 48 264 194 41 200 83 272 151 130 227 134 34 22 212 113 131 226 112 292 24 127 236 90 16 10 159 193 19 161 85 187 274 89 17 223 7 191 104 38 126 100 185 222 145 225 82 90 230 262 5 276 87 79 39 11 21 53 147 3 278 216 263 35 75 72 241 79 122 247 281 267 185 85 27 95 219 71 242 292 161 245 69 144 35 295 235 228 50 179 20 287 172 139 23 128 152 129 14 95 36 234 38 72 218 18 85 164 22 52 231 261 280 131 89 291 162 161 108 142 14 172 276 141 258 15 148 2 65 177 265 56 198 31 31 168 286 119 173 192 286 256 100 25 43 275 88 101 184 9 106 227 294 213 189 52 94 143 150 77 70 6 192 126 77 124 185 62 263 58 136 109 27 41 40 201 105 14 149 215 104 175 53 230 219 ^ 635 1 239 133 297 115 119 248 195 9 183 166 199 238 130 279 74 121 163 19 265 270 257 66 8 126 204 71 294 234 246 89 173 101 170 29 85 44 154 256 154 202 210 115 65 5 108 163 73 209 58 103 176 264 267 40 25 10 41 28 28 82 26 113 258 69 26 167 202 156 171 277 159 297 7 231 174 104 88 70 83 29 31 67 111 44 46 69 80 111 289 2 82 234 1 33 160 246 280 285 27 79 108 72 260 84 149 124 289 247 38 147 55 222 4 105 245 32 211 272 226 133 52 59 206 194 6 265 25 201 153 253 236 161 212 30 188 261 195 254 239 79 54 28 273 138 39 167 148 212 184 132 49 141 65 196 220 89 281 288 244 120 106 57 137 127 62 33 123 78 142 222 58 49 232 177 22 129 68 168 6 74 13 275 244 174 50 144 83 237 218 174 158 32 157 29 239 287 241 202 65 59 52 250 19 20 214 45 12 218 282 46 106 248 249 53 270 12 10 95 271 15 28 136 269 100 204 279 182 9 38 110 286 84 240 236 215 156 117 34 72 152 96 75 33 69 134 55 77 247 192 91 142 168 114 62 87 67 165 287 33 15 190 68 131 137 235 249 107 214 99 255 205 228 256 63 90 85 206 285 118 191 34 280 40 270 66 253 182 217 225 184 78 5 54 219 86 64 247 246 35 229 14 224 218 228 102 119 3 139 96 129 276 56 80 165 233 89 227 45 157 274 295 200 295 92 108 217 17 296 203 14 133 106 3 193 40 116 122 266 236 7 268 43 242 151 39 113 204 125 238 22 92 30 242 205 282 200 50 36 195 163 127 153 45 49 87 121 109 75 278 125 147 209 166 91 51 56 188 53 8 180 148 158 240 45 103 31 208 55 185 135 266 182 63 281 97 132 194 197 78 250 110 132 140 253 290 105 275 298 118 37 90 193 94 60 209 112 47 263 110 78 196 166 145 294 43 134 263 264 22 283 12 255 151 284 169 117 279 128 65 250 164 76 227 99 101 261 141 11 252 233 143 171 32 103 85 152 42 31 245 123 24 198 135 212 238 76 36 286 275 53 62 124 235 4 51 2 244 66 162 70 291 17 105 91 88 224 27 116 276 210 24 252 79 199 84 186 292 128 11 7 177 230 17 242 259 226 187 295 146 52 5 262 107 160 155 168 60 18 221 55 131 191 179 37 252 25 255 97 41 82 271 169 271 223 215 11 61 121 18 262 53 216 68 23 249 161 158 86 101 16 85 98 98 44 100 13 167 57 100 258 223 269 254 148 266 128 119 194 251 22 38 56 43 97 95 26 59 15 82 80 57 46 15 136 24 44 191 125 93 265 179 145 140 99 47 18 54 165 42 276 2 136 178 88 278 71 203 122 21 180 94 214 153 199 292 74 67 219 231 120 160 1 224 272 172 189 264 213 96 237 164 230 171 186 153 ^ 638 1 72 92 152 285 87 254 275 211 241 293 77 284 55 229 201 35 140 135 179 2 18 63 284 298 62 93 300 42 283 201 64 73 189 244 4 292 52 253 120 46 113 146 181 247 74 279 41 186 203 251 263 90 266 95 186 138 184 223 61 61 68 175 107 6 207 81 114 207 139 74 14 175 172 73 153 110 112 27 150 11 98 285 152 20 221 146 239 113 88 14 139 38 181 189 208 265 5 88 50 273 24 51 91 55 287 67 49 176 233 31 281 257 8 64 37 55 258 134 89 111 231 58 292 288 186 174 17 209 25 170 216 197 169 61 32 41 215 136 4 234 92 145 84 155 54 168 243 208 200 239 48 21 68 204 40 60 178 177 87 196 108 197 205 195 18 5 23 284 26 296 147 64 44 256 190 33 196 79 264 151 130 223 126 34 14 204 105 127 218 112 292 16 119 228 82 4 299 159 185 19 153 81 179 274 85 9 219 296 183 104 30 126 92 181 218 141 225 70 90 230 262 294 268 75 75 39 300 13 49 147 300 278 216 255 35 75 68 233 67 114 243 273 267 185 77 19 95 215 71 238 288 157 241 57 144 23 291 227 228 46 171 12 289 283 172 131 19 124 148 125 2 83 36 230 26 60 214 10 73 160 10 44 227 257 280 131 77 291 162 161 100 142 14 168 272 141 254 3 144 295 57 173 257 44 198 23 19 160 282 111 173 192 278 252 88 21 39 271 80 89 176 298 98 227 286 213 185 48 86 135 150 69 58 299 188 118 73 124 177 58 263 54 132 109 15 29 36 201 93 6 149 215 100 171 41 222 36 237 133 293 113 117 248 193 9 183 162 197 234 128 279 70 119 163 15 265 270 255 64 8 122 204 69 294 232 242 89 169 97 166 27 85 38 152 256 154 200 210 115 61 3 108 161 71 209 54 103 176 262 265 34 21 10 37 26 24 80 24 109 258 69 22 165 202 154 171 277 155 297 1 229 172 102 86 70 83 29 29 67 107 42 40 67 78 109 287 2 76 230 298 33 160 246 278 281 21 75 104 66 260 78 145 120 289 247 38 145 55 222 103 241 28 211 270 226 131 48 57 202 190 4 263 25 199 149 251 234 157 212 30 184 259 195 254 239 77 48 28 269 136 33 167 146 210 180 128 43 137 65 192 220 85 281 286 242 118 102 57 137 123 58 27 121 78 138 220 56 47 232 177 22 129 68 168 74 7 275 240 174 46 142 79 235 218 170 158 30 155 25 235 283 237 198 59 59 52 246 13 20 214 39 6 214 282 46 106 246 249 47 268 10 8 93 271 15 22 136 269 100 200 275 182 7 32 106 282 82 240 232 213 156 115 32 70 148 96 69 29 65 134 53 71 245 188 89 140 164 112 56 83 65 163 287 31 9 190 62 129 133 235 247 103 212 95 251 205 224 252 59 88 79 206 285 116 187 28 276 263 ^ 640 0 264 66 253 176 211 219 181 69 5 51 216 77 58 241 243 32 223 11 224 215 225 102 113 3 136 93 123 273 56 74 165 230 86 224 39 157 268 289 197 295 83 105 217 14 293 203 5 127 103 193 37 116 122 260 236 7 268 37 242 145 33 110 201 125 238 13 89 293 27 239 202 279 194 50 27 189 157 127 153 45 43 78 121 106 69 272 119 141 203 166 82 42 50 188 53 5 177 148 152 234 42 100 22 205 46 182 132 263 179 63 275 97 129 194 191 72 250 107 132 137 247 290 99 296 272 295 118 37 81 190 94 60 206 109 47 260 110 75 193 163 139 288 43 128 257 258 19 277 12 252 148 278 166 117 276 125 62 247 164 76 221 96 101 261 138 8 246 227 143 168 32 97 79 149 39 31 245 123 21 192 135 206 235 70 33 286 269 50 62 121 232 1 45 295 244 60 156 64 288 8 105 91 82 218 27 113 270 204 18 249 79 199 84 183 286 128 5 1 171 227 17 236 259 223 187 292 140 49 301 256 104 154 149 165 54 18 299 215 49 125 188 179 28 252 22 255 91 32 82 268 163 265 220 209 2 58 115 9 259 47 210 65 14 243 158 155 86 98 16 82 92 95 38 94 10 161 48 97 255 217 266 248 142 266 122 119 191 248 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 191 122 84 259 173 142 140 99 44 15 54 159 42 276 301 130 172 79 275 62 197 119 15 180 91 208 150 193 289 71 61 219 231 114 157 1 221 272 169 186 264 207 87 237 161 224 165 180 41 72 89 152 284 87 252 274 210 241 293 77 284 52 229 199 34 138 134 178 17 60 282 298 61 93 299 39 283 200 62 71 187 242 4 290 49 251 120 43 113 144 181 245 73 278 40 185 201 251 261 88 265 94 186 138 184 223 61 58 65 175 107 6 205 81 114 207 137 71 11 174 170 73 152 108 110 25 148 11 98 283 150 17 221 146 237 111 88 13 139 36 179 189 207 263 3 86 48 273 21 51 90 54 285 65 49 175 233 29 280 257 6 64 36 53 257 132 87 111 229 58 291 288 184 173 16 208 24 170 214 197 169 60 30 41 213 134 2 234 92 145 83 155 51 166 243 208 200 238 48 21 66 203 40 59 178 176 85 196 106 195 204 194 15 4 23 283 24 296 146 61 43 254 189 31 195 78 262 151 130 222 124 34 12 202 103 126 216 112 292 14 117 226 80 1 297 159 183 19 151 80 177 274 84 7 218 294 181 104 28 126 90 180 217 140 225 67 90 230 262 292 266 72 74 39 298 11 48 147 300 278 216 253 35 75 67 231 64 112 242 271 267 185 75 17 95 214 71 237 287 156 240 54 144 20 290 225 228 45 169 10 287 282 172 129 18 123 147 124 301 80 36 229 23 57 213 8 70 159 7 42 226 256 280 131 213 ^ 640 0 291 162 161 94 142 14 165 269 141 251 298 141 292 51 170 251 35 198 17 10 154 279 105 173 192 272 249 79 18 36 268 74 80 170 292 92 227 280 213 182 45 80 129 150 63 49 296 185 112 70 124 171 55 263 51 129 109 6 20 33 201 84 149 215 97 168 32 216 27 234 133 287 110 114 248 190 9 183 156 194 228 125 279 64 116 163 9 265 270 252 61 8 116 204 66 294 229 236 89 163 91 160 24 85 29 149 256 154 197 210 115 55 108 158 68 209 48 103 176 259 262 25 15 10 31 23 18 77 21 103 258 69 16 162 202 151 171 277 149 297 296 226 169 99 83 70 83 29 26 67 101 39 31 64 75 106 284 2 67 224 295 33 160 246 275 275 12 69 98 57 260 69 139 114 289 247 38 142 55 222 298 100 235 22 211 267 226 128 42 54 196 184 1 260 25 196 143 248 231 151 212 30 178 256 195 254 239 74 39 28 263 133 24 167 143 207 174 122 34 131 65 186 220 79 281 283 239 115 96 57 137 117 52 18 118 78 132 217 53 44 232 177 22 129 68 168 295 74 302 275 234 174 40 139 73 232 218 164 158 27 152 19 229 277 231 192 50 59 52 240 4 20 214 30 301 208 282 46 106 243 249 38 265 7 5 90 271 15 13 136 269 100 194 269 182 4 23 100 276 79 240 226 210 156 112 29 67 142 96 60 23 59 134 50 62 242 182 86 137 158 109 47 77 62 160 287 28 190 53 126 127 235 244 97 209 89 245 205 218 246 53 85 70 206 285 113 181 19 270 30 260 66 253 172 207 215 179 63 5 49 214 71 54 237 241 30 219 9 224 213 223 102 109 3 134 91 119 271 56 70 165 228 84 222 35 157 264 285 195 295 77 103 217 12 291 203 303 123 101 302 193 35 116 122 256 236 7 268 33 242 141 29 108 199 125 238 7 87 289 25 237 200 277 190 50 21 185 153 127 153 45 39 72 121 104 65 268 115 137 199 166 76 36 46 188 53 3 175 148 148 230 40 98 16 203 40 180 130 261 177 63 271 97 127 194 187 68 250 105 132 135 243 290 95 294 270 293 118 37 75 188 94 60 204 107 47 258 110 73 191 161 135 284 43 124 253 254 17 273 12 250 146 274 164 117 274 123 60 245 164 76 217 94 101 261 136 6 242 223 143 166 32 93 75 147 37 31 245 123 19 188 135 202 233 66 31 286 265 48 62 119 230 303 41 291 244 56 152 60 286 2 105 91 78 214 27 111 266 200 14 247 79 199 84 181 282 128 1 301 167 225 17 232 259 221 187 290 136 47 299 252 102 150 145 163 50 18 299 211 45 121 186 179 22 252 20 255 87 26 82 266 159 261 218 205 300 56 111 3 257 43 206 63 8 239 156 153 86 96 16 80 88 93 34 90 8 157 42 95 253 213 264 244 138 266 118 119 189 246 79 ^ 650 0 24 35 22 76 81 26 38 8 68 80 43 32 1 129 24 44 191 118 72 251 165 138 140 99 40 11 54 151 42 276 301 122 164 67 271 50 189 115 7 180 87 200 146 185 285 67 53 219 231 106 153 1 217 272 165 182 264 199 75 237 157 216 157 172 33 72 77 152 280 87 244 270 206 241 293 77 284 40 229 191 30 130 130 174 298 13 48 274 298 57 93 295 27 283 196 54 63 179 234 4 282 37 243 120 31 113 136 181 237 69 274 36 181 193 251 253 80 261 90 186 138 184 223 61 46 53 175 107 6 197 81 114 207 129 59 305 170 162 73 148 100 102 17 140 11 98 275 142 5 221 146 229 103 88 9 139 28 171 189 203 255 301 78 40 273 9 51 86 50 277 57 49 171 233 21 276 257 304 64 32 45 253 124 79 111 221 58 287 288 176 169 12 204 20 170 206 197 169 56 22 41 205 126 300 234 92 145 79 155 39 158 243 208 200 234 48 21 58 199 40 55 178 172 77 196 98 187 200 190 3 23 279 16 296 142 49 39 246 185 23 191 74 254 151 130 218 116 34 4 194 95 122 208 112 292 6 109 218 72 295 289 159 175 19 143 76 169 274 80 305 214 286 173 104 20 126 82 176 213 136 225 55 90 230 262 284 258 60 70 39 290 3 44 147 300 278 216 245 35 75 63 223 52 104 238 263 267 185 67 9 95 210 71 233 283 152 236 42 144 8 286 217 228 41 161 2 279 278 172 121 14 119 143 120 293 68 36 225 11 45 209 58 155 301 34 222 252 280 131 62 291 162 161 90 142 14 163 267 141 249 294 139 290 47 168 247 29 198 13 4 150 277 101 173 192 268 247 73 16 34 266 70 74 166 288 88 227 276 213 180 43 76 125 150 59 43 294 183 108 68 124 167 53 263 49 127 109 14 31 201 78 302 149 215 95 166 26 212 21 232 133 283 108 112 248 188 9 183 152 192 224 123 279 60 114 163 5 265 270 250 59 8 112 204 64 294 227 232 89 159 87 156 22 85 23 147 256 154 195 210 115 51 304 108 156 66 209 44 103 176 257 260 19 11 10 27 21 14 75 19 99 258 69 12 160 202 149 171 277 145 297 292 224 167 97 81 70 83 29 24 67 97 37 25 62 73 104 282 2 61 220 293 33 160 246 273 271 6 65 94 51 260 63 135 110 289 247 38 140 55 222 296 98 231 18 211 265 226 126 38 52 192 180 305 258 25 194 139 246 229 147 212 30 174 254 195 254 239 72 33 28 259 131 18 167 141 205 170 118 28 127 65 182 220 75 281 281 237 113 92 57 137 113 48 12 116 78 128 215 51 42 232 177 22 129 68 168 291 74 298 275 230 174 36 137 69 230 218 160 158 25 150 15 225 273 227 188 44 59 52 236 304 20 214 24 297 204 282 46 106 241 249 32 263 5 3 88 271 15 7 136 269 100 190 265 182 2 17 96 283 ^ 649 0 76 240 220 207 156 109 26 64 136 96 51 17 53 134 47 53 239 176 83 134 152 106 38 71 59 157 287 25 298 190 44 123 121 235 241 91 206 83 239 205 212 240 47 82 61 206 285 110 175 10 264 24 254 66 253 166 201 209 176 54 5 46 211 62 48 231 238 27 213 6 224 210 220 102 103 3 131 88 113 268 56 64 165 225 81 219 29 157 258 279 192 295 68 100 217 9 288 203 297 117 98 302 193 32 116 122 250 236 7 268 27 242 135 23 105 196 125 238 305 84 283 22 234 197 274 184 50 12 179 147 127 153 45 33 63 121 101 59 262 109 131 193 166 67 27 40 188 53 172 148 142 224 37 95 7 200 31 177 127 258 174 63 265 97 124 194 181 62 250 102 132 132 237 290 89 291 267 290 118 37 66 185 94 60 201 104 47 255 110 70 188 158 129 278 43 118 247 248 14 267 12 247 143 268 161 117 271 120 57 242 164 76 211 91 101 261 133 3 236 217 143 163 32 87 69 144 34 31 245 123 16 182 135 196 230 60 28 286 259 45 62 116 227 303 35 285 244 50 146 54 283 300 105 91 72 208 27 108 260 194 8 244 79 199 84 178 276 128 302 298 161 222 17 226 259 218 187 287 130 44 296 246 99 144 139 160 44 18 299 205 39 115 183 179 13 252 17 255 81 17 82 263 153 255 215 199 294 53 105 301 254 37 200 60 306 233 153 150 86 93 16 77 82 90 28 84 5 151 33 92 250 207 261 238 132 266 112 119 186 243 6 22 32 19 73 79 26 35 7 66 80 41 30 306 128 24 44 191 117 69 249 163 137 140 99 39 10 54 149 42 276 301 120 162 64 270 47 187 114 5 180 86 198 145 183 284 66 51 219 231 104 152 1 216 272 164 181 264 197 72 237 156 214 155 170 31 72 74 152 279 87 242 269 205 241 293 77 284 37 229 189 29 128 129 173 297 12 45 272 298 56 93 294 24 283 195 52 61 177 232 4 280 34 241 120 28 113 134 181 235 68 273 35 180 191 251 251 78 260 89 186 138 184 223 61 43 50 175 107 6 195 81 114 207 127 56 303 169 160 73 147 98 100 15 138 11 98 273 140 2 221 146 227 101 88 8 139 26 169 189 202 253 300 76 38 273 6 51 85 49 275 55 49 170 233 19 275 257 303 64 31 43 252 122 77 111 219 58 286 288 174 168 11 203 19 170 204 197 169 55 20 41 203 124 299 234 92 145 78 155 36 156 243 208 200 233 48 21 56 198 40 54 178 171 75 196 96 185 199 189 306 23 278 14 296 141 46 38 244 184 21 190 73 252 151 130 217 114 34 2 192 93 121 206 112 292 4 107 216 70 293 287 159 173 19 141 75 167 274 79 304 213 284 171 104 18 126 80 175 212 135 225 52 90 230 262 282 256 57 69 39 288 1 43 147 300 278 216 243 35 75 62 221 49 102 237 261 267 140 ^ 649 1 61 3 95 207 71 230 280 149 233 33 144 308 283 211 228 38 155 305 273 275 172 115 11 116 140 117 287 59 36 222 2 36 206 303 49 152 295 28 219 249 280 131 53 291 162 161 84 142 14 160 264 141 246 288 136 287 41 165 241 20 198 7 304 144 274 95 173 192 262 244 64 13 31 263 64 65 160 282 82 227 270 213 177 40 70 119 150 53 34 291 180 102 65 124 161 50 263 46 124 109 300 5 28 201 69 299 149 215 92 163 17 206 12 229 133 277 105 109 248 185 9 183 146 189 218 120 279 54 111 163 308 265 270 247 56 8 106 204 61 294 224 226 89 153 81 150 19 85 14 144 256 154 192 210 115 45 304 108 153 63 209 38 103 176 254 257 10 5 10 21 18 8 72 16 93 258 69 6 157 202 146 171 277 139 297 286 221 164 94 78 70 83 29 21 67 91 34 16 59 70 101 279 2 52 214 290 33 160 246 270 265 306 59 88 42 260 54 129 104 289 247 38 137 55 222 293 95 225 12 211 262 226 123 32 49 186 174 305 255 25 191 133 243 226 141 212 30 168 251 195 254 239 69 24 28 253 128 9 167 138 202 164 112 19 121 65 176 220 69 281 278 234 110 86 57 137 107 42 3 113 78 122 212 48 39 232 177 22 129 68 168 285 74 292 275 224 174 30 134 63 227 218 154 158 22 147 9 219 267 221 182 35 59 52 230 298 20 214 15 291 198 282 46 106 238 249 23 260 2 85 271 15 307 136 269 100 184 259 182 308 8 90 266 74 240 216 205 156 107 24 62 132 96 45 13 49 134 45 47 237 172 81 132 148 104 32 67 57 155 287 23 294 190 38 121 117 235 239 87 204 79 235 205 208 236 43 80 55 206 285 108 171 4 260 20 250 66 253 162 197 205 174 48 5 44 209 56 44 227 236 25 209 4 224 208 218 102 99 3 129 86 109 266 56 60 165 223 79 217 25 157 254 275 190 295 62 98 217 7 286 203 293 113 96 302 193 30 116 122 246 236 7 268 23 242 131 19 103 194 125 238 301 82 279 20 232 195 272 180 50 6 175 143 127 153 45 29 57 121 99 55 258 105 127 189 166 61 21 36 188 53 307 170 148 138 220 35 93 1 198 25 175 125 256 172 63 261 97 122 194 177 58 250 100 132 130 233 290 85 289 265 288 118 37 60 183 94 60 199 102 47 253 110 68 186 156 125 274 43 114 243 244 12 263 12 245 141 264 159 117 269 118 55 240 164 76 207 89 101 261 131 1 232 213 143 161 32 83 65 142 32 31 245 123 14 178 135 192 228 56 26 286 255 43 62 114 225 303 31 281 244 46 142 50 281 296 105 91 68 204 27 106 256 190 4 242 79 199 84 176 272 128 300 296 157 220 17 222 259 216 187 285 126 42 294 242 97 140 135 158 40 18 299 201 35 111 181 179 7 252 15 255 77 11 82 261 149 251 69 ^ 655 0 191 286 49 97 293 250 29 192 56 298 225 149 146 86 89 16 73 74 86 20 76 1 143 21 88 246 199 257 230 124 266 104 119 182 239 309 14 20 7 61 71 26 23 3 58 80 33 22 302 124 24 44 191 113 57 241 155 133 140 99 35 6 54 141 42 276 301 112 154 52 266 35 179 110 308 180 82 190 141 175 280 62 43 219 231 96 148 1 212 272 160 177 264 189 60 237 152 206 147 162 23 72 62 152 275 87 234 265 201 241 293 77 284 25 229 181 25 120 125 169 293 8 33 264 298 52 93 290 12 283 191 44 53 169 224 4 272 22 233 120 16 113 126 181 227 64 269 31 176 183 251 243 70 256 85 186 138 184 223 61 31 38 175 107 6 187 81 114 207 119 44 295 165 152 73 143 90 92 7 130 11 98 265 132 301 221 146 219 93 88 4 139 18 161 189 198 245 296 68 30 273 305 51 81 45 267 47 49 166 233 11 271 257 299 64 27 35 248 114 69 111 211 58 282 288 166 164 7 199 15 170 196 197 169 51 12 41 195 116 295 234 92 145 74 155 24 148 243 208 200 229 48 21 48 194 40 50 178 167 67 196 88 177 195 185 299 306 23 274 6 296 137 34 34 236 180 13 186 69 244 151 130 213 106 34 305 184 85 117 198 112 292 307 99 208 62 285 279 159 165 19 133 71 159 274 75 300 209 276 163 104 10 126 72 171 208 131 225 40 90 230 262 274 248 45 65 39 280 304 39 147 300 278 216 235 35 75 58 213 37 94 233 253 267 185 57 310 95 205 71 228 278 147 231 27 144 304 281 207 228 36 151 303 269 273 172 111 9 114 138 115 283 53 36 220 307 30 204 301 43 150 291 24 217 247 280 131 47 291 162 161 80 142 14 158 262 141 244 284 134 285 37 163 237 14 198 3 300 140 272 91 173 192 258 242 58 11 29 261 60 59 156 278 78 227 266 213 175 38 66 115 150 49 28 289 178 98 63 124 157 48 263 44 122 109 296 310 26 201 63 297 149 215 90 161 11 202 6 227 133 273 103 107 248 183 9 183 142 187 214 118 279 50 109 163 306 265 270 245 54 8 102 204 59 294 222 222 89 149 77 146 17 85 8 142 256 154 190 210 115 41 304 108 151 61 209 34 103 176 252 255 4 1 10 17 16 4 70 14 89 258 69 2 155 202 144 171 277 135 297 282 219 162 92 76 70 83 29 19 67 87 32 10 57 68 99 277 2 46 210 288 33 160 246 268 261 302 55 84 36 260 48 125 100 289 247 38 135 55 222 291 93 221 8 211 260 226 121 28 47 182 170 305 253 25 189 129 241 224 137 212 30 164 249 195 254 239 67 18 28 249 126 3 167 136 200 160 108 13 117 65 172 220 65 281 276 232 108 82 57 137 103 38 308 111 78 118 210 46 37 232 177 22 129 68 168 281 74 288 275 220 174 26 132 59 225 218 150 158 20 145 5 215 263 100 ^ 661 1 176 26 59 52 224 292 20 214 6 285 192 282 46 106 235 249 14 257 311 309 82 271 15 301 136 269 100 178 253 182 308 311 84 260 71 240 210 202 156 104 21 59 126 96 36 7 43 134 42 38 234 166 78 129 142 101 23 61 54 152 287 20 288 190 29 118 111 235 236 81 201 73 229 205 202 230 37 77 46 206 285 105 165 307 254 14 244 66 253 156 191 199 171 39 5 41 206 47 38 221 233 22 203 1 224 205 215 102 93 3 126 83 103 263 56 54 165 220 76 214 19 157 248 269 187 295 53 95 217 4 283 203 287 107 93 302 193 27 116 122 240 236 7 268 17 242 125 13 100 191 125 238 295 79 273 17 229 192 269 174 50 309 169 137 127 153 45 23 48 121 96 49 252 99 121 183 166 52 12 30 188 53 307 167 148 132 214 32 90 304 195 16 172 122 253 169 63 255 97 119 194 171 52 250 97 132 127 227 290 79 286 262 285 118 37 51 180 94 60 196 99 47 250 110 65 183 153 119 268 43 108 237 238 9 257 12 242 138 258 156 117 266 115 52 237 164 76 201 86 101 261 128 310 226 207 143 158 32 77 59 139 29 31 245 123 11 172 135 186 225 50 23 286 249 40 62 111 222 303 25 275 244 40 136 44 278 290 105 91 62 198 27 103 250 184 310 239 79 199 84 173 266 128 297 293 151 217 17 216 259 213 187 282 120 39 291 236 94 134 129 155 34 18 299 195 29 105 178 179 310 252 12 255 71 2 82 258 143 245 210 189 284 48 95 291 249 27 190 55 296 223 148 145 86 88 16 72 72 85 18 74 141 18 87 245 197 256 228 122 266 102 119 181 238 308 12 17 4 58 69 26 20 2 56 80 31 20 301 123 24 44 191 112 54 239 153 132 140 99 34 5 54 139 42 276 301 110 152 49 265 32 177 109 307 180 81 188 140 173 279 61 41 219 231 94 147 1 211 272 159 176 264 187 57 237 151 204 145 160 21 72 59 152 274 87 232 264 200 241 293 77 284 22 229 179 24 118 124 168 292 7 30 262 298 51 93 289 9 283 190 42 51 167 222 4 270 19 231 120 13 113 124 181 225 63 268 30 175 181 251 241 68 255 84 186 138 184 223 61 28 35 175 107 6 185 81 114 207 117 41 293 164 150 73 142 88 90 5 128 11 98 263 130 299 221 146 217 91 88 3 139 16 159 189 197 243 295 66 28 273 303 51 80 44 265 45 49 165 233 9 270 257 298 64 26 33 247 112 67 111 209 58 281 288 164 163 6 198 14 170 194 197 169 50 10 41 193 114 294 234 92 145 73 155 21 146 243 208 200 228 48 21 46 193 40 49 178 166 65 196 86 175 194 184 297 306 23 273 4 296 136 31 33 234 179 11 185 68 242 151 130 212 104 34 304 182 83 116 196 112 292 306 97 206 60 283 277 159 163 19 131 70 157 274 74 299 208 274 161 104 8 126 70 170 207 130 225 37 90 230 194 ^ 643 0 268 242 36 62 39 274 301 36 147 300 278 216 229 35 75 55 207 28 88 230 247 267 185 51 307 95 202 71 225 275 144 228 18 144 298 278 201 228 33 145 300 263 270 172 105 6 111 135 112 277 44 36 217 301 21 201 298 34 147 285 18 214 244 280 131 38 291 162 161 74 142 14 155 259 141 241 278 131 282 31 160 231 5 198 311 294 134 269 85 173 192 252 239 49 8 26 258 54 50 150 272 72 227 260 213 172 35 60 109 150 43 19 286 175 92 60 124 151 45 263 41 119 109 290 304 23 201 54 294 149 215 87 158 2 196 311 224 133 267 100 104 248 180 9 183 136 184 208 115 279 44 106 163 303 265 270 242 51 8 96 204 56 294 219 216 89 143 71 140 14 85 313 139 256 154 187 210 115 35 304 108 148 58 209 28 103 176 249 252 309 309 10 11 13 312 67 11 83 258 69 310 152 202 141 171 277 129 297 276 216 159 89 73 70 83 29 16 67 81 29 1 54 65 96 274 2 37 204 285 33 160 246 265 255 296 49 78 27 260 39 119 94 289 247 38 132 55 222 288 90 215 2 211 257 226 118 22 44 176 164 305 250 25 186 123 238 221 131 212 30 158 246 195 254 239 64 9 28 243 123 308 167 133 197 154 102 4 111 65 166 220 59 281 273 229 105 76 57 137 97 32 302 108 78 112 207 43 34 232 177 22 129 68 168 275 74 282 275 214 174 20 129 53 222 218 144 158 17 142 313 209 257 211 172 20 59 52 220 288 20 214 281 188 282 46 106 233 249 8 255 311 309 80 271 15 297 136 269 100 174 249 182 308 307 80 256 69 240 206 200 156 102 19 57 122 96 30 3 39 134 40 32 232 162 76 127 138 99 17 57 52 150 287 18 284 190 23 116 107 235 234 77 199 69 225 205 198 226 33 75 40 206 285 103 161 303 250 10 240 66 253 152 187 195 169 33 5 39 204 41 34 217 231 20 199 313 224 203 213 102 89 3 124 81 99 261 56 50 165 218 74 212 15 157 244 265 185 295 47 93 217 2 281 203 283 103 91 302 193 25 116 122 236 236 7 268 13 242 121 9 98 189 125 238 291 77 269 15 227 190 267 170 50 305 165 133 127 153 45 19 42 121 94 45 248 95 117 179 166 46 6 26 188 53 307 165 148 128 210 30 88 300 193 10 170 120 251 167 63 251 97 117 194 167 48 250 95 132 125 223 290 75 284 260 283 118 37 45 178 94 60 194 97 47 248 110 63 181 151 115 264 43 104 233 234 7 253 12 240 136 254 154 117 264 113 50 235 164 76 197 84 101 261 126 310 222 203 143 156 32 73 55 137 27 31 245 123 9 168 135 182 223 46 21 286 245 38 62 109 220 303 21 271 244 36 132 40 276 286 105 91 58 194 27 101 246 180 308 237 79 199 84 171 262 128 295 291 147 215 17 212 259 219 ^ 652 1 187 278 112 35 287 228 90 126 121 151 26 18 299 187 21 97 174 179 302 252 8 255 63 306 82 254 135 237 206 181 276 44 87 283 245 19 182 51 288 215 144 141 86 84 16 68 64 81 10 66 312 133 6 83 241 189 252 220 114 266 94 119 177 234 304 4 5 308 46 61 26 8 314 48 80 23 12 297 119 24 44 191 108 42 231 145 128 140 99 30 1 54 131 42 276 301 102 144 37 261 20 169 105 303 180 77 180 136 165 275 57 33 219 231 86 143 1 207 272 155 172 264 179 45 237 147 196 137 152 13 72 47 152 270 87 224 260 196 241 293 77 284 10 229 171 20 110 120 164 288 3 18 254 298 47 93 285 313 283 186 34 43 159 214 4 262 7 223 120 1 113 116 181 217 59 264 26 171 173 251 233 60 251 80 186 138 184 223 61 16 23 175 107 6 177 81 114 207 109 29 285 160 142 73 138 80 82 313 120 11 98 255 122 291 221 146 209 83 88 315 139 8 151 189 193 235 291 58 20 273 295 51 76 40 257 37 49 161 233 1 266 257 294 64 22 25 243 104 59 111 201 58 277 288 156 159 2 194 10 170 186 197 169 46 2 41 185 106 290 234 92 145 69 155 9 138 243 208 200 224 48 21 38 189 40 45 178 162 57 196 78 167 190 180 289 306 23 269 312 296 132 19 29 226 175 3 181 64 234 151 130 208 96 34 300 174 75 112 188 112 292 302 89 198 52 275 269 159 155 19 123 66 149 274 70 295 204 266 153 104 126 62 166 203 126 225 25 90 230 262 264 238 30 60 39 270 299 34 147 300 278 216 225 35 75 53 203 22 84 228 243 267 185 47 305 95 200 71 223 273 142 226 12 144 294 276 197 228 31 141 298 259 268 172 101 4 109 133 110 273 38 36 215 297 15 199 296 28 145 281 14 212 242 280 131 32 291 162 161 70 142 14 153 257 141 239 274 129 280 27 158 227 315 198 309 290 130 267 81 173 192 248 237 43 6 24 256 50 44 146 268 68 227 256 213 170 33 56 105 150 39 13 284 173 88 58 124 147 43 263 39 117 109 286 300 21 201 48 292 149 215 85 156 312 192 307 222 133 263 98 102 248 178 9 183 132 182 204 113 279 40 104 163 301 265 270 240 49 8 92 204 54 294 217 212 89 139 67 136 12 85 309 137 256 154 185 210 115 31 304 108 146 56 209 24 103 176 247 250 305 307 10 7 11 310 65 9 79 258 69 308 150 202 139 171 277 125 297 272 214 157 87 71 70 83 29 14 67 77 27 311 52 63 94 272 2 31 200 283 33 160 246 263 251 292 45 74 21 260 33 115 90 289 247 38 130 55 222 286 88 211 314 211 255 226 116 18 42 172 160 305 248 25 184 119 236 219 127 212 30 154 244 195 254 239 62 3 28 239 121 304 167 131 195 150 98 314 107 65 162 220 55 281 271 227 103 72 57 137 93 28 308 ^ 670 0 105 78 106 204 40 31 232 177 22 129 68 168 269 74 276 275 208 174 14 126 47 219 218 138 158 14 139 310 203 251 205 166 11 59 52 214 282 20 214 308 275 182 282 46 106 230 249 316 252 311 309 77 271 15 291 136 269 100 168 243 182 308 301 74 250 66 240 200 197 156 99 16 54 116 96 21 314 33 134 37 23 229 156 73 124 132 96 8 51 49 147 287 15 278 190 14 113 101 235 231 71 196 63 219 205 192 220 27 72 31 206 285 100 155 297 244 4 234 66 253 146 181 189 166 24 5 36 201 32 28 211 228 17 193 313 224 200 210 102 83 3 121 78 93 258 56 44 165 215 71 209 9 157 238 259 182 295 38 90 217 316 278 203 277 97 88 302 193 22 116 122 230 236 7 268 7 242 115 3 95 186 125 238 285 74 263 12 224 187 264 164 50 299 159 127 127 153 45 13 33 121 91 39 242 89 111 173 166 37 314 20 188 53 307 162 148 122 204 27 85 294 190 1 167 117 248 164 63 245 97 114 194 161 42 250 92 132 122 217 290 69 281 257 280 118 37 36 175 94 60 191 94 47 245 110 60 178 148 109 258 43 98 227 228 4 247 12 237 133 248 151 117 261 110 47 232 164 76 191 81 101 261 123 310 216 197 143 153 32 67 49 134 24 31 245 123 6 162 135 176 220 40 18 286 239 35 62 106 217 303 15 265 244 30 126 34 273 280 105 91 52 188 27 98 240 174 305 234 79 199 84 168 256 128 292 288 141 212 17 206 259 208 187 277 110 34 286 226 89 124 119 150 24 18 299 185 19 95 173 179 300 252 7 255 61 304 82 253 133 235 205 179 274 43 85 281 244 17 180 50 286 213 143 140 86 83 16 67 62 80 8 64 312 131 3 82 240 187 251 218 112 266 92 119 176 233 303 2 2 306 43 59 26 5 314 46 80 21 10 296 118 24 44 191 107 39 229 143 127 140 99 29 54 129 42 276 301 100 142 34 260 17 167 104 302 180 76 178 135 163 274 56 31 219 231 84 142 1 206 272 154 171 264 177 42 237 146 194 135 150 11 72 44 152 269 87 222 259 195 241 293 77 284 7 229 169 19 108 119 163 287 2 15 252 298 46 93 284 311 283 185 32 41 157 212 4 260 4 221 120 315 113 114 181 215 58 263 25 170 171 251 231 58 250 79 186 138 184 223 61 13 20 175 107 6 175 81 114 207 107 26 283 159 140 73 137 78 80 312 118 11 98 253 120 289 221 146 207 81 88 315 139 6 149 189 192 233 290 56 18 273 293 51 75 39 255 35 49 160 233 316 265 257 293 64 21 23 242 102 57 111 199 58 276 288 154 158 1 193 9 170 184 197 169 45 41 183 104 289 234 92 145 68 155 6 136 243 208 200 223 48 21 36 188 40 44 178 161 55 196 76 165 189 179 287 306 23 268 311 296 131 16 28 224 174 1 180 63 232 151 130 207 94 34 299 172 73 111 186 112 292 301 87 196 50 273 267 159 153 235 ^ 658 1 117 63 143 274 67 292 201 260 147 104 313 126 56 163 200 123 225 16 90 230 262 258 232 21 57 39 264 296 31 147 300 278 216 219 35 75 50 197 13 78 225 237 267 185 41 302 95 197 71 220 270 139 223 3 144 288 273 191 228 28 135 295 253 265 172 95 1 106 130 107 267 29 36 212 291 6 196 293 19 142 275 8 209 239 280 131 23 291 162 161 64 142 14 150 254 141 236 268 126 277 21 155 221 309 198 306 284 124 264 75 173 192 242 234 34 3 21 253 44 35 140 262 62 227 250 213 167 30 50 99 150 33 4 281 170 82 55 124 141 40 263 36 114 109 280 294 18 201 39 289 149 215 82 153 306 186 301 219 133 257 95 99 248 175 9 183 126 179 198 110 279 34 101 163 298 265 270 237 46 8 86 204 51 294 214 206 89 133 61 130 9 85 303 134 256 154 182 210 115 25 304 108 143 53 209 18 103 176 244 247 299 304 10 1 8 307 62 6 73 258 69 305 147 202 136 171 277 119 297 266 211 154 84 68 70 83 29 11 67 71 24 305 49 60 91 269 2 22 194 280 33 160 246 260 245 286 39 68 12 260 24 109 84 289 247 38 127 55 222 283 85 205 311 211 252 226 113 12 39 166 154 305 245 25 181 113 233 216 121 212 30 148 241 195 254 239 59 313 28 233 118 298 167 128 192 144 92 308 101 65 156 220 49 281 268 224 100 66 57 137 87 22 292 103 78 102 202 38 29 232 177 22 129 68 168 265 74 272 275 204 174 10 124 43 217 218 134 158 12 137 308 199 247 201 162 5 59 52 210 278 20 214 304 271 178 282 46 106 228 249 312 250 311 309 75 271 15 287 136 269 100 164 239 182 308 297 70 246 64 240 196 195 156 97 14 52 112 96 15 312 29 134 35 17 227 152 71 122 128 94 2 47 47 145 287 13 274 190 8 111 97 235 229 67 194 59 215 205 188 216 23 70 25 206 285 98 151 293 240 230 66 253 142 177 185 164 18 5 34 199 26 24 207 226 15 189 313 224 198 208 102 79 3 119 76 89 256 56 40 165 213 69 207 5 157 234 255 180 295 32 88 217 316 276 203 273 93 86 302 193 20 116 122 226 236 7 268 3 242 111 318 93 184 125 238 281 72 259 10 222 185 262 160 50 295 155 123 127 153 45 9 27 121 89 35 238 85 107 169 166 31 310 16 188 53 307 160 148 118 200 25 83 290 188 314 165 115 246 162 63 241 97 112 194 157 38 250 90 132 120 213 290 65 279 255 278 118 37 30 173 94 60 189 92 47 243 110 58 176 146 105 254 43 94 223 224 2 243 12 235 131 244 149 117 259 108 45 230 164 76 187 79 101 261 121 310 212 193 143 151 32 63 45 132 22 31 245 123 4 158 135 172 218 36 16 286 235 33 62 104 215 303 11 261 244 26 122 30 271 276 105 91 48 184 27 96 236 170 303 232 79 199 84 166 252 128 290 283 ^ 649 1 133 208 17 198 259 204 187 273 102 30 282 218 85 116 111 146 16 18 299 177 11 87 169 179 292 252 3 255 53 296 82 249 125 227 201 171 266 39 77 273 240 9 172 46 278 205 139 136 86 79 16 63 54 76 56 312 123 312 78 236 179 247 210 104 266 84 119 172 229 299 315 311 298 31 51 26 314 314 38 80 13 2 292 114 24 44 191 103 27 221 135 123 140 99 25 317 54 121 42 276 301 92 134 22 256 5 159 100 298 180 72 170 131 155 270 52 23 219 231 76 138 1 202 272 150 167 264 169 30 237 142 186 127 142 3 72 32 152 265 87 214 255 191 241 293 77 284 316 229 161 15 100 115 159 283 319 3 244 298 42 93 280 303 283 181 24 33 149 204 4 252 313 213 120 307 113 106 181 207 54 259 21 166 163 251 223 50 246 75 186 138 184 223 61 1 8 175 107 6 167 81 114 207 99 14 275 155 132 73 133 70 72 308 110 11 98 245 112 281 221 146 199 73 88 315 139 319 141 189 188 225 286 48 10 273 285 51 71 35 247 27 49 156 233 312 261 257 289 64 17 15 238 94 49 111 191 58 272 288 146 154 318 189 5 170 176 197 169 41 313 41 175 96 285 234 92 145 64 155 315 128 243 208 200 219 48 21 28 184 40 40 178 157 47 196 68 157 185 175 279 306 23 264 307 296 127 4 24 216 170 314 176 59 224 151 130 203 86 34 295 164 65 107 178 112 292 297 79 188 42 265 259 159 145 19 113 61 139 274 65 290 199 256 143 104 311 126 52 161 198 121 225 10 90 230 262 254 228 15 55 39 260 294 29 147 300 278 216 215 35 75 48 193 7 74 223 233 267 185 37 300 95 195 71 218 268 137 221 318 144 284 271 187 228 26 131 293 249 263 172 91 320 104 128 105 263 23 36 210 287 194 291 13 140 271 4 207 237 280 131 17 291 162 161 60 142 14 148 252 141 234 264 124 275 17 153 217 305 198 304 280 120 262 71 173 192 238 232 28 1 19 251 40 29 136 258 58 227 246 213 165 28 46 95 150 29 319 279 168 78 53 124 137 38 263 34 112 109 276 290 16 201 33 287 149 215 80 151 302 182 297 217 133 253 93 97 248 173 9 183 122 177 194 108 279 30 99 163 296 265 270 235 44 8 82 204 49 294 212 202 89 129 57 126 7 85 299 132 256 154 180 210 115 21 304 108 141 51 209 14 103 176 242 245 295 302 10 318 6 305 60 4 69 258 69 303 145 202 134 171 277 115 297 262 209 152 82 66 70 83 29 9 67 67 22 301 47 58 89 267 2 16 190 278 33 160 246 258 241 282 35 64 6 260 18 105 80 289 247 38 125 55 222 281 83 201 309 211 250 226 111 8 37 162 150 305 243 25 179 109 231 214 117 212 30 144 239 195 254 239 57 309 28 229 116 294 167 126 190 140 88 304 97 65 152 220 45 281 178 ^ SHS Type 3 Strings 40 1 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 8 16 11 16 15 18 18 3 20 2 17 17 16 ^ SHS Type 1 Hashes DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 ^ 59C4526AA2CC59F9A5F56B5579BA7108E7CCB61A ^ 6E42FB84067CFF056C43A49E484997AF23190879 ^ C63FBB9A87171A176E6E054890E29A8C5F125F6C ^ 3109E33C1C4B9A0169D1599169D0E5A520A1E71C ^ 9195E1E73CC68D7170F44BD1D83CB624BC87FA0B ^ 64F7C374527278C0436DBC8DE5AABEC2BBF634BC ^ 154B622EA426FB151B1FF1BE1CE871752B9EDEB4 ^ 12BDD00FD4038756CBCF8ECDAD1B0CD862603CD8 ^ 6700F93E1691E83735279E167F67AF61FEE9813B ^ 84AF20A06799F366435BA20F99B9A10955B6D276 ^ C622FE003FD16220357F88FC6B9DE4789E77C321 ^ C8DEA5A98DADA1F9662D5C150618140A150ECA46 ^ FBB7127E77A39D856EC849D755C868CA7B9F11E9 ^ B7D8A7A39AB33ED8C3AFD8F76201BF0904149437 ^ 154535460A12B9E100E251BB3A4D4DBCD80A309A ^ 82FC6020C7A9B62F334F7156ADA608532DCA6A3B ^ 9DD980B8073B32D21E9B2324F982024375C2951F ^ 419F97A9899486DC53C58C761CEB564314FD47BD ^ A212E43EBFB31388F64C0C0B0B1CC7019704B744 ^ D8F1623C186A5615F58E846C9D164F35A8956E44 ^ AA32848DE1499365730A3650A3A7703FD404259A ^ 79BDB01E55B61A8C1AFBF63D3CE2DCCAB8CF3DFB ^ 23BF3164A448A727BA71457EBA9FCFABFBAC4F70 ^ BA26E846EBEF7434B63F5862FDA005A1CEB5656E ^ 98622869A474EA85FE575CD979354248141A14A7 ^ 5C9E7E6951D386205542DA0680E07E60EC61D64E ^ 8EF07A02A7023AA0E6EE4BE1518627A521D1F9D5 ^ CDEA382A5DFDA1C633F8BBC77F291F40E8801CE3 ^ 3C0A709FEF85DDBCC1B362AA162010461F31AECD ^ 10ABD6B8D97E688AF5CDA7955CD3CC0850A4A75F ^ 0EC53133F7FF955CA37D25491B592DFC0256BF23 ^ 1A46A67FEED1604523C062AACC2455223B366D05 ^ FA3DD749E8F3D9029D9261F25157B3C0E2DF6834 ^ 43DCAC2CF20E7CCB1DED6E379CC302F302655F3B ^ 8BA25BDF331671CCB4B60961E4AF356224027862 ^ AC3A3EA0FB8727334A4478ED165128581BBC5BEA ^ CA4406A231EA2CA06CD1D8F3C77FEF9118B1501A ^ 5B83465B8EED14871FB51D9E6CE499FB2E4B4209 ^ 9445F521861946D4063E0CA3F41F580855A7454E ^ C2410140818962F95506B407AE8514F11F892AEC ^ F8F826FE0D93F415426ADB6956242116CBAB2426 ^ C803F7539AA036CBB31B735238120FB85180D8C8 ^ 162EB5163692D9BC7B4529D214BBB932157361B6 ^ D4B0D876A1952ADB5D27A1A6BF71BCF22731A4C5 ^ CB5CD26AA39E45F248706604EDB9A2DB8EDC1BF6 ^ F1AC987F30FF0375F6115C0CCD6E22DDFD0FAFE7 ^ 692E209D3A6A0228EB9823DCB738B16BDF97A4E9 ^ FB9E1E71F7645EEEEB3DDE66716DC44444CD657C ^ D51F071E360D96124DA49AD37E37DE17B564920D ^ 0667AFCDBB82B4213447D0B22006DC4A1320CD21 ^ 8FBFC65FEB2565F2FB8A9966B74702350C87CF40 ^ 8A8BBCD6AF76E71067EB0AF54F90EE5AC2B5882F ^ 8D831EF2344E336CC27281227185A34356B856A6 ^ DE7AA7424F92CBC50966FC4E6A577F98905998FC ^ 1064EE6BEF704F3A618CB9C58F299B22A4D34293 ^ 95F8CF7E864FEBBF77E46067063D08D5175FC508 ^ 79381F230970F120D19B115BF864C794878E7797 ^ D82A30F49538561D5A7D1324ECAD321DD05E1202 ^ 5926CEEAE43D29A7BE4C0EDCA626C43ABE00416A ^ 563458C9F2C16C5AF96915FCD9306F1D9BA579C9 ^ C92B0BD604E45D7479AE19F641B2DB067E4CA774 ^ D69D013EE5C871D3AE3E388090BC1AAF9852A83C ^ 7C341ECDEE7298605933465EA9ADBE7E044C8A79 ^ 83EC687D22A13EDDCD470C52C45276A6E1554982 ^ 6D27928F014269CEC4E8745EB73FA714BE2DC62E ^ 75C0BF312C05231DAF7E9CD4CA33ACA78BCAA59A ^ 015D799C602DD4E30D2C0104A57B1E214A423D66 ^ D2F43ECAD20F0B4C57DD07D3CECE562B6B72C7FB ^ 27948CE5A56D57248D4DF683DC3FE023D2B9B43A ^ 2D5A984BF32DE28242744406469E18B7A5178A97 ^ FFC5C4ECF0CC051320E071D14C7DCA4A4DDA305A ^ CED8A5487AD13AF0003129659DE2556183836C54 ^ 599BB509863CC5D275416F6DB6C5D2BD827DC347 ^ 3981DAC895DDB9294D933C1CE78828E3A558B152 ^ 91EB715904123D326B23ACD684DFBD7203CABECB ^ 5A9AC8C3705AF14DDE50E6CF2FE5B0C15C4BD282 ^ E2620DFB42B5ECAF85F590A71DF696906AC41C4D ^ CBAADDA7B5DB389BF1775AE50040081A05A0EE48 ^ AAF80D079F3F980BF9D5366C5B1991A3E3D9FDCE ^ 2A861F616604C526ACB157732DC431E81BC9A1F6 ^ FBDB22AA0B87718F464C0D1AA39695A1BDCE053F ^ 4331BA331522D4F9CD6137858DB9AA16AC95316E ^ 33F6BFE23A4C0E04B8BF642CD96437EF0055AAF7 ^ 2046138F7899FDB2063CD84B84E821525172C03B ^ E4FDC812C5F7A37FC7A81005F1E78BFF59666887 ^ 6477F931AC20B2FCE1C92171FA4DCF2D266B3DC5 ^ ED0DD516FA7FE2DB7AFCC3DBEED0879A0C10F1C2 ^ FCEDA0311C085368A5751BCAD8EAED2063C2D40A ^ 23EB08B5100C8FBAF7B3049887A11CC531B6CD78 ^ A6C42B757DF078A69FFF6819A8ABC46E1B09F435 ^ 0615EE4840B1F1CD628636D1B4F4495639DEDEBC ^ E2288110007AE6DBCCFC74B7735F4D94B0AA10A1 ^ 159E01DC348EB067E90A63BC6FEFBF4C45A01F9A ^ A16286459CC989AE662C731F3D7D0CD487DCCB3B ^ 8FDAFE2DE37215E142E27A65A881F80E0430BF49 ^ 1BF978B58D98FC15731F4111E7C7A49F9CFD7C65 ^ C1F61CD4B4DB14AA60C6448C0398EEC72107826C ^ 5CF0A7F6F46A730CD9103A54F1EC8A7549FA5788 ^ FDC104217940BE5A7AD1C02D128B31747C972A5C ^ DFF58BEF4FF418D26A35B55215CE419D3579A194 ^ 3A2EFD444F4AA7A3DB9765E027CE5D82B51F6737 ^ EB616B6F97C5BFD02C1B9E4AFBA8A5151DD4167F ^ 62F31F9A28D0587BD8253601A7EFB698B03205FA ^ E87645B2CB7DF66DA2771ABE0CEDA0F625FC8AFA ^ E801C3071CA6AEE278B222747BFA819C118A2DDD ^ EC70223BD963C122E4FCE2928934DDD2D7661CBC ^ 82261D26377A5A5DC69E0F39D0BBF59A1B2B2248 ^ 2E4DE781E4407AE536F70DC5A5DBEB178DBA2FC3 ^ AD3D958B884CAA28D5858DA103463C300862DEE6 ^ 2A6A563C7FE33129637FABB4D40F5F0EE8B5C500 ^ 7EA6003A8BEF4D5BFA6BFEFBCB6A5B3B1A3B7991 ^ 6DDC620DB14882575D5BA1219284CF1C3068094F ^ 91AD7E588EC829739C3632656DE1915AC23C8CF5 ^ 311A491C1B5D8A26EA2A77A36B5D53FDABA1FB2A ^ 9D4B752AA8FDAF92897B03C4D65B65EABBDF062C ^ C569FF6F0592664F690B008EE7A12EDA5740F0C7 ^ 1AE35E9CD3D0A8A165B2758E1DC4F9D1CD30FBF9 ^ 819A83318700EA861CB69F6CD8ED4ECD78CC3CB7 ^ 98099B550A82CE22EFAE48B5935F636D5814FDB4 ^ CFADB998167DB289A7C17BA94DF7EDA00B29085E ^ 3F5A90A8F757936987938DFB95F10239F91AC264 ^ 7402265908EEA5DA183490FEF2EA2E55C9FC2862 ^ EA6EF0F7050EDA6B78F35597E85B7A85AE0097E4 ^ 73F2780548F7C79E15945D7EE2A3E03B30DF35CA ^ 8EC3C93C7307E14E9C65F26DD847CEB195DE277A ^ CFBC571A35B82FB0B7CB59753C4E8DE36A751195 ^ 3C4802A956CF93A148B9034FB8F041ECD8DD4532 ^ 5DA269C1D5CCEE3C7A66E31BD9F5E0B83BA06CE1 ^ 706D90C00800DB9790AF66788D1B3DC81E3FF7A1 ^ 59AC856447FDD27421C52EA66E465C64C5033722 ^ EACA9E82D043F2B6E12E64CF03D82ED92FD6A64D ^ 8160755BA09C74F79DE8F9496BF0C9248DB7D45E ^ 8CE4390C185BDFC8BC9C4D3BEB1AB757C44F6434 ^ 1A1ADB628EB7B9CAA821AE9DE417E09A42A97113 ^ 97C4F92A46EF3F9169A977E1643C10745ECDAA4E ^ 408E53C03D10E2B32222F2B54D118AC4D65A9386 ^ 710628E811C207784E3255DA8432CE6E14B61FE7 ^ 4F6DB622778F4B1B6203BD239312D86589F1B261 ^ 888AD8FC1CA5B893294FDB8FC94AB7762018C1F8 ^ AE36C2F54223BC082DDA0D528B70B2AEA190779C ^ 4BD2BF914223DCD0CBBCC444323FBF0E487F27B6 ^ 7526D5DF7B2ECFAC7BFF62DD7A4B5F38463305F8 ^ 0ED7C87B68F50813AAD5E50159CBE0BBF9BF05D2 ^ 4D5CD4E40A6668893EEA15F025ECB8187475DF4F ^ D38446E842C0A94F175B772BDC707CD2EE79D098 ^ DDA868BC2903C55CF273F48E9B92C09D90CD0179 ^ 0841268B95ECFAAB9FE3787BA7261227A1F23294 ^ D3DDF20B4C0DB668421DE1F242B65A8C83FA867B ^ 112F3CF7DACA7527819D16704EB41302A4EE52AA ^ 96072A3EA4463A156B3BD9EAEC16ADB0905160C9 ^ 715F195F09E3EAD3D70AE51DEF1C9709500C0A6A ^ 8A112CA82CFEB5F3001B7A00591462F4120DDC02 ^ 50FC91E915270D1202F6FC8792BE16ECB73CE405 ^ 907736EC45BE7BEDA1B154EA282C51B5795991F8 ^ 05D49462991278720EB44BEA656AB4442C8845C3 ^ 6FD56D08A2D4630F72AC97E3C94A9575F3046729 ^ DD1883376CF713C8D7AEBFEC60D51FF8E2A806E8 ^ E0457FE00F9DEEE958DD6AD948EDF9CD9412F73A ^ BA6538E91B276504C84E213B325B4A7703E924B4 ^ C20A9B848503650DE9463B9992EB977422BB53DF ^ BA4A565E5C0F9FAC89D55A2B784F291C7BAD4255 ^ 6510E09AAD8288AB81CA54DD5656DF57D0EABBE6 ^ 33996C9C5AD04883BCEB9771A5C4A272F88550B1 ^ 7B96F3C1272AD765DBDC35A59243F6A8F75FA351 ^ 5AA76B16EA4DFB267D88FF7DBE4F055184A56E56 ^ 33B9CCEB1A6EDC8C91F6034245B2E3AAC898C678 ^ 701A32FC0B1163BC55DB76FA46F69B574B3803A0 ^ 5D6F44A4B5175BA873BFA3369DC8BFB0AD1AC26C ^ 0727F12D8E554EDCB435AE3BD6425B197DF6EE2E ^ 6E1F46DC4FAD671759AC969998694BD79326246E ^ 85233F9CFD0780BD60240A22E037C14EB8286C33 ^ B66CC7332341FA9261D96362F0BBD7B676F95E02 ^ 782A78F2FC32E0B627702C541341ED28B009BB6F ^ 6B7935265C529880DA5B166EDD660BAE14A770A9 ^ 49C298B1C10D380BACE26E907C213C90052D7523 ^ 49CE4D4FF9FFF6724DA032FF33F8C5A7792D24E2 ^ CD2C4F19C12B086C071BB6B20E8E8210AFDD2D50 ^ 39710F77BE564C417C80CB6E4B87BE72FA805A40 ^ F74A6A45F5B2979B5E773007B90804F322F13AD8 ^ 6FD6A34339047CF13F777C4B7D9E287F499FB19C ^ FDB04F04D3B364A6953C341E343E310F2383A655 ^ 981E8717538CE98998E950EAD28596B527736841 ^ E099987DB0CC61CF607C9852336CDAF478DEE33F ^ E9C42F25A3E3542D1510DD09BF516AD809D42702 ^ F7E580FB21C725CBEA563B193896862B9BEF7F24 ^ D778A3287F68F47B0AA421410292D47805997A94 ^ 534DFE759735723649EDC89BCB063C0CCFEEC34F ^ 9381FB5BD26677A7760FC0288532755062986DF1 ^ 27E97EE829820399595DA0A0047B74D3C4E0DBF1 ^ D38450071D1B079A9FD518D2F317C83C33094F43 ^ 0221B8E4D2FA66D2EBE1B04E679662CE41405E48 ^ B9BC4FDC4A5CE00EFB911C3062D6F33304701C28 ^ 461B4206618B766C89E6D9AB2F8DB07903860234 ^ 122A9306B102F2C50B7364E1D24FECB0662E2958 ^ 61E91F5D167066EC904134AB1C4F9D116C9D3E80 ^ 6B7558BD8F4D3C5914A9AB5D7418F7DB77583B55 ^ CE48EA94843854555DC48D24D32405DAB9DBA612 ^ 5A722AAC576F4078C001D06DA91C28131A4F92C5 ^ 9B8FE0F1E6573CC6832BA69DEC9F6E646228A374 ^ F98429CA2799E5CAAEDDFB168B782A54384EF0A8 ^ 142877754AB95F57AA541CB978BA400E812AECC9 ^ 6D84D053CCD9E68CAC5780892409F61B39DDFD48 ^ B58CC9CE0AE3DAAA02E3C040100D4B568D29E0FA ^ 17FB18FA32A8237D32CF83A9664B1B2E40DC5B11 ^ C7F65E54E608CEF1C7A120BE8A29FA6C94B680D2 ^ 9C46329BA34077394B439C5476B91D9DF019BA76 ^ 3612B381B80A1DF6DA75AB2656BD5BA8DE6996B5 ^ EDD9BCA1C431200D3234C099791C81D8605091AB ^ C1951DDECB9796C0D39ED9AFCCBB65200AEAB0CB ^ 55E4F7846D9B90D8B31EAA5B9371D395590B6528 ^ 5D40B432ADBDF3A01355FFFDDBA47586B3DC7C52 ^ AF5C675D2249F4CD20E70DC9E18B88D3ACFBD6BF ^ B0EB6796A21876FAAF50FCDBA2EB121C4B742166 ^ 3C577C70B76810DDF9AD579910347312B881C30F ^ 0C16897D20C5F352FA6110C70F9A8C33CA35CA21 ^ DBE0B4341526060C5B37576F6B972A1EB8954059 ^ 1567B10E33FBBE20033F5A52EB810348ED154F19 ^ C1E47289412D3ACC208620A1EA676CE2815DD4FB ^ ABC227EFFDCE3758061C77971860247E850382AD ^ B29EACEC903BB8AF7CC1A63516163640FFE62822 ^ 5C8976A1A4FCC6B6FAB5EE631E3CDC561ED5FB10 ^ 1A1EA5107CC46BE909DF8165C3EFEE8676161991 ^ 268E86BA3A81FADDB20F74DD44C5BC71A98C3D08 ^ 05057E5E7934AC9A9141D39B8D4F5EA6AA14F74F ^ C03EA72C4D68945726DF63803564E434426302BA ^ 54AF20BFBFEAD6BB2DD68E65D39D427DF7E17FD9 ^ FDE938DB0843A844DC0F6601497A39ACF167D6DD ^ ED0292D0BD869B66E80014824A3D7886CD6D3590 ^ 749B69964F5C0D9D02BF5CF903B2E56D09CF1B9C ^ 6B143D30366C45F159B83A8D1AE8AAEC88E44136 ^ 01169D65E71014946D0BF64BF439068978AA5B3A ^ 4C36E0A8C19C0AA6C80DF0611BA3404C1025E9CC ^ A4DA9EEC2F682AF5B2EE7CC8525EB07DF66E5945 ^ F1349AD0124D11613CFA46D498671484E5F37790 ^ 6A8E82D2D27D3EDD6E8B119F746761B8FE83182A ^ 52E7C7C4AE02659953079DAE20F442353EE2BB29 ^ 49C8D822724274B85DE62D9DF586FE880AF396E6 ^ 57866C0BB976B4F8AAA7ACF3C9A0F700E73216DA ^ 541A675DD37C5D6F2CF242163A5CF6B728DF9995 ^ 55B26D9344D4D644CBB69C4789473543262E8B91 ^ 3A8F3F0A96297020EEA583E9A280D53E0248DE26 ^ D1FF7A0CD0B69A76B5B80D2BB5736B8440DA7F7B ^ 53E715FA39D3732F38FB4748D46409D998D67973 ^ 377781ABB4AB4E974B9C1670867E74F87AB4950A ^ 8E7DA96971265ACC0FF7C381127C966DF9F9F13A ^ 28038713A33ACAAC730FB4DDC3A707886E598DD5 ^ 5F6BD44D07A1C811D5B75661A61BB69A81444EE2 ^ D465E6C767BD02D457D601765DD0FE5521BA2AC7 ^ 487D9E02912004E961968F387C21A65A0E653AE7 ^ 1F54DF00052B3740301C43420CC2CB85B2770095 ^ 7C5BB678083868EB817E616BD09421B910021649 ^ 4D31526E4E2FE3BD6DD4B3F59DC2EE2A52A9FB42 ^ 669F9FA9D71FB92D51ADE15C70742FB31B013901 ^ 38D1E74FE26AA43D45DABC160DEFF113B7740211 ^ 3724EF50CDEAEB856123BEBB190F38834461664D ^ E2634112D2977A179D4C9AF35F220D3A626AA04C ^ F14CF8133FF66A3E20D25E5DCFF70605F6B8A0BC ^ 809E04A38340D010B78B5287C8FDD20C391FB61B ^ E5349D4D6EC31E2CF41001DFC440ADFF6D25B4F7 ^ 139F25FDC344EC2456F6E4DD9938F65693F0CB2D ^ 7C628B0954D4340B0851C89F1106589C5C6465C6 ^ E65E65D7050258B6B6B5B35866840B5ACE0DBF0D ^ 77D33B87E0C13529D3AAC4D6606213EFE81FF398 ^ 5BA456BA49ABE50BBCB772FAACB71D4F3AECBD45 ^ 801A21F7AB73585AE3531058DB9512BD69BA5CB1 ^ 192AC4D5210EC863604FC1BA388AEA8455D4175D ^ FD9F103EDFC4CC9F9C424266EE54A79C1C987F9E ^ 361AC46D96A69DD6E416D4563D7C69D3B487EFC1 ^ 3A7629045C0193FE08928F7D41B801827593116B ^ 545B2F5FD015F81BDE1DAFAFCA184D25590560C9 ^ FEF2C50DA33621206450E21D92951B25385991A3 ^ 913A417AC1ECE08952A60E0035F70993F161EF05 ^ 4FFC95481F6F625B1B8E67B133F11619CE5C1460 ^ 5D6D0765B156FE028780331B6A53F84DFB130F0A ^ 2C5EC89F1018D34AB11E0CB6FDC812F82470B168 ^ 34D62CDFF955233FE7A5308925C24CBCDC0579B8 ^ 1148994D30F80C5689D7BB19CFBE33546872B4FC ^ 074FCA22A8A63F446C8D196612F7C812C22CCD8B ^ 228FE29FD13928D8FF0B850E50DB41DB406EFCBB ^ EFF7BBF8F2F7DF36AD51EF3D748AAB8D8DAB7B7D ^ C3AEA6AA17971C0A143ACE54A8CF515F9EEB0BD6 ^ 4C3A980E40602D4621C2AF1BEB1CAE27DF19AD32 ^ E5CE2A41C72229D584E40FBA67C697EFA08F451D ^ 64A5368264959C73FB0A12F85D4FA16F8E25FF08 ^ 8FB770AEC165A93A6D99A0DC52F38444E0313073 ^ BCFF3C5E5C56876A3DD8C4C90D4E819B67D71394 ^ 0EF20523757E25611C49C1F259D94381B08FB90A ^ 5D9F05DAB91C46ADDCE4B163C6FCDFB5230BDFFA ^ 11B3BDC5F3BE09148DA07CD42EC9C28C718D6A5B ^ 1EAD76EF18840B3176296FA57791D832B7E4035C ^ AF8EBCBBDF5B8CFC203FBD8644B154445690B02E ^ 0A156DAD35A10AA7E41C5CB3B3043A051B7180B6 ^ 9B3E5F797BA246E5DE660B9A36E52C204BACE822 ^ 78780359CD24A2B7157FD6D55CDFA6F9DE149FF5 ^ F2DADAB4275633F7ECDFA971D824A31B1C8D6643 ^ EA68BA8F16D8368E6673A5C5AEE86BA5C36F2D97 ^ 788AA9451196E2BDD031E747B098D73BE113C093 ^ 18FE259B3573F52F23DAD33F05D9C91942B516DD ^ 0E4787F46AE8D5D7CC9589B76D00D60983079D75 ^ 148E4FDF031CAFB726099DCD1EB591BC2F24D179 ^ 3981DF8658AC2FA5C3151A424262324D41940DBA ^ 3C50A3800636EF877D89059F66CD697A9DF44BD1 ^ D9BAB0471E2DB97FD5F3A42884DFC708768F62F9 ^ 52DD1063326E2550B6EF40D5EE4E1AD67C7BB6BA ^ 13CA27827127C698810AECA158DCAA7894F0C912 ^ 086BDB17EC1B8CAC68030A56FBD4C741D4F95DBA ^ F7F389BC5ED225BD6399CC43EF22AFD77E895D06 ^ 67F173AD3A24C26E95E2EA8B37FC0259B1DE955C ^ A7F348A3B6F67CCF7C7C69ED065B3FBFA832A8A2 ^ ECECBB25354468FB62AC87D5CEB688E4A671DC42 ^ 62330BC400108DFAFF298EFB76BDC28CDC153AC1 ^ BB0ECF9CB3CE448B4EA9C57CF5F1F997F81082B4 ^ 12C9741672CE8DBA14CC66AF3338B61E234F9E68 ^ DB4CB5961A2FF6964CEDECAED3DA03D140112EA4 ^ 45E4D2BE3D9729BE9F69ADB245A5A9CC75064534 ^ E35253550C84BEFC26C2E97F0C236CFF1D85C36F ^ 7D6D950A168107702CE3B6BCEF9298F9C8FC8F3C ^ 812F459AB5887364D1F2A9A00CBEE5FC352C39A2 ^ 7EE27F33C59B68C34604416D38606BD3F5CB6B06 ^ D57E2A4F15DF5C50F2485909EE3149735C6DFB84 ^ 3D12D88B61EF0972808D8CAD41D8A16AA7ECCC87 ^ CF9A7CEA9B105ADAB6BBA3CFB6D090B76603F7CE ^ 1D43CA164CAD0B616BE5763D7F5EA88355953F4B ^ 3600F085A53FB0115C26DA90D1180FD34EEB6301 ^ E9F9C088C30A37E6CDF067F724BE6C4786F27C9E ^ 2BB86B47EA34400D434F8F4F94830CBDA9D4E573 ^ 3255A7D9A7A0B56D0D9C665EC13F7A8C8F05DA7B ^ 453597500A7D5BEC8CFB950926A2BFC0F92E149B ^ A15EC452476870AC459B942F6A6B73822A07899C ^ 5B1821BFAF917BAB3DB1284A1D1FD40EA011BCBC ^ 8DDC25C7CA330A18CF39827B7CBEC00B874AF193 ^ 283832F45BB5E69649FC10DD607BAF8BAD61783E ^ F39426F9C0474596B0251F0CBB5F92385D862D24 ^ 714E32DD5BB8FCC75B1013E6F1F56F96D97B36F2 ^ 988AC4592D50113B13F6EDB5C113A22E4D0F518E ^ 93BF1463788B7F4A4A06AD4C17482DC260797A3F ^ 5532535ACC8AC5668977B2A2F322B23AEB443DB2 ^ 85CC7AF0929F206FA44FCAACDC24C4E78345BD80 ^ 392196E3F2F4074D1D485A52119012D8C05740B6 ^ 3BA88B91F1EA18E712292301FBBC375E9B48BFC6 ^ 3DAAD1DAB1795F2C1C8C5CF5305B549ABFB85398 ^ 6EC93AFA3AB617708276E99066FDC331C84F028D ^ CDA219303B91AF3C3FBD0B926758914984AD7C8D ^ 599CE24745EB5408554077354BD10A65F6BC3037 ^ 0798C1B53F949D643F7BD66C194715E7CAFC6E19 ^ A17230F164E98AB83AC1141730B23389F0EB473D ^ 2C2B95173F1B06165E17EAE36A53C7AB641267C3 ^ A7F408EF449DC92961617D4C51B55AE4E4536E97 ^ 2266C5133B6D6B08A09897AEFA355C768F718C6C ^ 343F10EE6EB34DF005E749D1C4A98F64537272B1 ^ 90EEB76B126E632308F8655FD49C52000027AA48 ^ C7EA3C7D4AA8DCBE9580C4434075017934268419 ^ 455D4E7C988356A56588C40313D28E425AE219F9 ^ 5C0F3090992138D34B4E33029CF83A64ED8AB03D ^ CB3C5288839D6FE79EB2E50D3AC34BBC4A942E46 ^ E605842205079D83BDD489DCF6F8A2D1EE074C60 ^ ABCBEC56EA20B6B369C85A931B2201FECB826F4A ^ 480C1CB97C3419DA610D9783E6047E6C9A6101A4 ^ 874818464DA1753D3AEDDB7D3B46E2D04614D7E6 ^ C95B65E3A37ED4A2FE2B27A2D52BF1BFD307ED20 ^ 5E188A4F625C05482BF161C45F5094844CE70461 ^ 6B2EBCFE74E0BF32480D4BCF9A5698A527AEBEAD ^ ABD3E28A2A528B7963EA8D8896651A17337304D9 ^ B873FDE2C312C2279EC8950EC2C2E9DF990F006F ^ 4F1A18714689BDB766AF686623BEF08DAFDFE1F5 ^ BA886793A89E7EC62692A8690164BF072EAF7AA4 ^ A15C8DDAA0448DE7B361552FC51AF0D72C0737FA ^ 6FB516CBB4CCE9681C44EFABABC7A26C79C79CB5 ^ C6DA89D3F7EC4D2FCDB36432042A78EAC9F04DC6 ^ 2A94A9023F7D54DB26C8C2A6A4C951126712C2E5 ^ B0F115B8BF0A1464A378420A1F1F574AA1869FC8 ^ A3C1794F58FFDC361BCAD4779B5DEF48E02ABD1A ^ 2DBA5D80C4B17167E715A8012876095577030D5C ^ 062C3CB7A059766125B368AD6C19BE8FAA981950 ^ ECEA96EB623919DF4E22FB106616EF1FB2ACF5AF ^ C0CD5E555861FFBCB2FF4045A46CE30AE6CA1758 ^ A0150D931980E1D82A21928837F7E9E198E5D1B9 ^ BF877B202812184CA74DE61FE34DB95BA2AC5D0B ^ C863A0D2232E901920752F2AF92C201FC73609B5 ^ C54E676209D81CFED2E7ECEA6F7E35A5459A58AE ^ CBF376E8571F81792AAC49BA7E1D7F41713ACDCE ^ 9CD248C07EEF6303C71901AC484F30788D9269F9 ^ AEA41C5B2260E0DC57094C5E1F80A70B85E79E77 ^ B1016F26E32624C5328566B243329A2F75A36D06 ^ 3EDE118F7E2764CC49FBC3873508D38A2C6A4592 ^ 03DF0C882FEED72F81B303414178976ABD089EEF ^ 2A8E36B6A545D1ABE7B02D6DDD782AE032F7ED41 ^ D90588E606FBDF3CC6030756DF92FB3729441E6F ^ BCC413133B6D84621B482A7D2163EA955AC733BF ^ BE1F36D34DEC54306EF20D8326FF603A716F4331 ^ A2BAE41EA01E8AE9D59F5E8E663D22C9F414B0F6 ^ D2295FE26206DE9ED169FEA487B198E7CA0DE78B ^ 06B13130DD10C94A24CB50DE6A612867F85E17FA ^ 2CF4C4F2F270AF63D7035903231CF7E7180E66E5 ^ 0A9EE3293A2C9B2ACC2F9B99BF17AAC618347857 ^ C338F14C156D8777ECFC36ADF1850B64EE9E6179 ^ E9BC6DA35AEB1CC399733CD0AD3B22E4E2C83E92 ^ 7A42F820210158AD33935CB77D78C28F9FE7A940 ^ ECDEFA7817A436E43C3DFA35069F87948181A58A ^ 761EBF336F1229BF80702C9C7798DAC37ACF3086 ^ 1975B716880B49BA0863136736942E688C9EEC7C ^ A4232C3227DBB91581B86FABB1C5AB0A29801DFC ^ 49947AF1D9488F146BE4C77782CB2FCF6EB13FC9 ^ A3402AE17DB9E6EC899B0E15973073CF9404A2DF ^ DCAFC2DC5BAB38629DFA0DE1454C300E5B9A2D66 ^ A7F915F745E30E4CF6AFFABF214AB6D950C66FAE ^ 764515277D4AF73A14FAE2D9CFA4F9BAF306CCB5 ^ B021EB08A436B02658EAA7BA3C88D49F1219C035 ^ B97FE9E1C5918FEFBEDD986B757CCF4EC4AFA75D ^ 6917353596BFAF1A5A06119ECDABB37CB017D71E ^ FCB4BCEBEBBAB66142AD2A5B35AB5DBF78C6A463 ^ BCA454B69F4486960C633D2C4453FD01D6758BCE ^ 5CD25E62AD97AA5DB3A9CEE99C58439DFBF6073B ^ E8405E583D31B3B8E8B365087F2AB391753324A4 ^ 39E32AE405420DEB07275224817B57187079886F ^ 63AC20AFAEDAFBFC018755F4CEB13A042BDEFDFE ^ 27245C74B61D19EA28FED81E59AA48EFC22946C9 ^ 7254C8F5A2DF0E747760E2EB353C4AB24E253602 ^ 32DD49B796ABCA76356AA9AB07D669CB7BC7F899 ^ B83F3FBE6DB38223253344E69C399C474E4C64A5 ^ B3E0EB484AE5B10B017F509730F350481A60F634 ^ A99FC247C177D66CBC6C21C10C21E10FB2F33EF9 ^ A7D033A946AA0315CD2E4B7025164B77E5979CBE ^ F2DE5CD912D5CFE727B353ADECB6B7FD11E80189 ^ 111BA90582E17CB5E1BB70AB72C99FCF647876A0 ^ 9AF7F1A742235C0E396F6D1319BD1104518F8475 ^ 923B3E5246FB50FB5448742B8EA8CF4920E70702 ^ CBFC4563334D104E4DF24443A295F4E9A7D7D4AA ^ 48F4BEDE76C6DDE9B72A9FED50D0BDBD0DF7E7AE ^ 2A21E7828C064DB0D684561622802C86A504DD37 ^ 2D599572D6E57A437A2A845546FBEF9F2FA11AD8 ^ CB4CFD92FFEFFDDFD87A4786D60E28C7622C71DF ^ FA6DB9D1EB92461454E7DADC36C9CE7A1F30C63E ^ 98C264B7CDF774C7D82F4DA5E1160AE4370665CB ^ D503D3C5CAF7A2D124A7F9F0E7D8D0F5E29B6F19 ^ AEFF5AF0023868EF6E3AD49F2C30D65E963B6308 ^ 73B1464B9D05509BE72E83C819F9D618B3121336 ^ 791774666D2629D4304BC81138B4D8A7599E77D6 ^ 362A2D419BAF263F1E77C5689F611AE301C044F2 ^ B4D4796D1BC1851DDB75F5D3BA3089D1D0E0A15D ^ B7C4FD404A73C0AE43FABAEB471FDB6F9B24A27C ^ B9DC118349DDAB37DD82B65E092277C1E2F20C5F ^ 144782913DF2FA8F76D210A7A321F362FA5DA779 ^ 29D64351A178E52EDDA9A4B2F5279B70F3FEF39C ^ 31098A70FB95128BECC2C729CE5A2A4BCA121845 ^ 9C05D6B171C60C37822CDBD7E8C1C57286E27461 ^ 6FF7C4960E35463A8FDB77844A29DDAD1FF04F53 ^ 2E08B9088646737620F1B448E81EA5E42C40C595 ^ AF2342D8F4BF12F9E524E44BCD42066F84620727 ^ 543A1A99B497DBB7776403F3252A9B2E11A0610A ^ A2A46BEF09D21A9BA32AAE4FCF7A846D128F0358 ^ 81960A20A755F84B3623D1E2A395EDB12DFDE73F ^ B016C90B350A5A9AD4C1F3AFE49E3EB21AAE8B7A ^ 41D03A8D79E8BAAE116C2F5573D869D97D7F6E0B ^ 831237F5BDAC37C58BA31F6131982AFE680BAC1F ^ 2E8ACF5FDE18542BDC2D0B95D3AED7FC48B5993B ^ 171763D880D45885EA61F5ED04BB51B79C6A2724 ^ 405AD282A2141C38D3D731F9DF630667064B9ED0 ^ 07F2ECB944D01DDF9C68AA68762BF07F385E7E6D ^ EB5FEBB813E4DD7BF852FB32466025F7D4E79DD9 ^ 52DE090DB027385F17C9FD41F61272525FE108B1 ^ 103E352A261134E1154ED3C312D890646FED38AE ^ 65C73969E35E8F307B518ABBDE85654CAD13D0C7 ^ FB380C0099EADED9ED8DD48D70E15C7A26E2F417 ^ EF9E122E0B8F968EF262E1A98BBFED7B461846B9 ^ 771A162BDE3CC4C07BE7A1DD25470286F133020E ^ 5F892353DC5C65A1D8C9510ACEC43DD96F432742 ^ 4E658B8743D510221B968F2C78C72A588A5DF6D6 ^ 5D5295ACEC24F8A52ECC5B174E4884732BD216E2 ^ 7791BD0E1C4136D97C46CCD66D36E98443C4182A ^ 515419AE59BE4E824E575E497F361C3382C21783 ^ 7669D0D083B3A0A7B631EE4871AD2A2AF8C512F9 ^ 90A1A9BD93501D9AFE5040DDEE395F94E5594EE4 ^ B8E48F79618CDE951296F1D28B87653C3CDA6FDB ^ FE94D5373EF009ED2C06F632C739717791EB6BB6 ^ B5C3871DA2466E4635DD3BCD085A2B8E222CE8F4 ^ 43032D022D24B65394F7A707C8441C2A7F3CD980 ^ 87C13448017DB3B6C553250C59DF4D3D57676788 ^ F38FCA4589543051935D4F1525710AB366161F22 ^ 921E3C3DE773F987452CAE28D3C10DF9804632DB ^ 32308D5BCA33E694071B8C17470C6469EDC1DCCE ^ AC5258297BA22FE60B464DEE22349C70FDFAB219 ^ 599322BC214D7248216F0C6ECF00CC34C792C5FB ^ 99EBA91FAFC27288B3FF32DE55BF17BC6D76B16C ^ 899DF7C21779CC0F54EDCD441051CACBD2B06941 ^ E5E0BA18BF3C99062BA444847876C5CA2DB8F9C4 ^ 94B8B90566B2E3BDDA8FF8D37BDD9F95CF9BE0B2 ^ 86422BAD65C5E0B22F02B9D1510B9D24F4227AC9 ^ 427694B772A08400381D472854FA5FD4D4CC1D62 ^ 3732DA8EBA84CB4591DD4A87BAE958635C85DD71 ^ D41C28C028E42AD1DF5057C97BB953B03AE8F6AE ^ 4C44286F5979D44AB4CA5E3776F30CA04CE539EC ^ E695D9B049A1497A86765195BA7884E8869142DE ^ 2A5DE9C5489375B8EFDB09CA29D32FDADAA07402 ^ 012356EB46A587763ECD1EC9F3114B8B8B7987B7 ^ 6B803DF07E5A47FBBE412149D8258B526D2BE96B ^ 14A1090C3B382482AAD5EF49B30D842317792745 ^ C2A576DE385017FA84855388EE6CB1F51F43A6C4 ^ 5746B8C88CE540313A0429E64841ECD0AD569299 ^ 298EFB87E9C09299DEC17171902682D919899C9D ^ 55AEB7930CD6202CD52E6513ED4C35824B574198 ^ ECDAA8404F88334E9C2C6FCC9209795581654C25 ^ 061FFFCE8F69BE0D0C9B63E30BB065C6CC73DF33 ^ 229F3A8BD2F6FFB5CE2DB330ACFBC4C4D7796D7F ^ 0BABE60803248059F3B05E06E273B5F41A619C9A ^ 5F496A5AAA1FC38B76069BF9F08C63777EE7530C ^ 91FC8994FAA03E9A2D9D565F04478C6DF035AFE3 ^ A68552B9049E192BBF98E82E2A69E405FFC2D93F ^ 7910393D1D9D8B876EC89FE9100320D371789C23 ^ 9B923F97F2D2B057950DC3C0E89981F22F96EC2F ^ 1EAD9C237CF3B1CB95E7ED79EF2E5842E9263447 ^ F51E5C202D698C75F8F0C2926081D4C28F641812 ^ 8842D9CD97868196B31F34C02BA63CE34493DCA2 ^ 26C8977BC36C3298582CE6703F62DFE4488E0DDE ^ 955BEF358ACA4D44E33F31051A3B92D96BA669E3 ^ 68D841B29DA285DA53A31E823462E794B3126914 ^ BB52C1806605DD37113035390D97036EFB3FE2BF ^ BC55772BC9B6066112512E1A8B633411B9508FA2 ^ BDD2CA4B43157C04CE7043F57B7E2610D3E175D9 ^ 8E493F25E110F6244FBD7585CF18F285933950EC ^ 650242DF99E985DE23A5CFC25C8CA72C80D7F23E ^ 56A061FE49B428798C329336D4B184BFE69C4102 ^ 59FF817CEE946CB948056227607A119F4C7DDA89 ^ BD4F03F1878CEA86E2AD981C6A80701E0AD30B4A ^ A635F528CC4028877184E8918CF73E1AEE6F777F ^ 15DCAE87F7E40CA577C61C2AA5B6D90F0CBE6DCE ^ D67BD85A353CEBB99ADE4CD86B54673DD6D64360 ^ 1619DE7229032800CDF071830CBCC3208B1EDB09 ^ 09DC18BEE0C2DD9A2C7189AA6D3DEB8B7CC41CE5 ^ 4165ED470D85FEDD9593577A9101306C31825E00 ^ C52942DABF4F9D72B31B2B3291705EF5201B3343 ^ 88296035BE79F5281B91C0F1006E57C28671CBF3 ^ 82593804880F168B9FF50D89CD149E9F263EB557 ^ 52E4F42FC2EC2EB7C0A728D2251A14A6C5EA5A00 ^ C91B243CBA2031B29F365BA4451FEFD6A902298A ^ 90F6F5A65E6BC9430A34C06631208AAE8B7555F5 ^ 7535D77C8809B4EA21678BF9686791418FC71931 ^ 027070AC6B5D77BFA0398B8AD556A23AB8E99EBF ^ B48335F6FB6EA27CE2156A1D3E00E42D3E3A8489 ^ B67303D71BF125F2441BFC599106177A32E43BAA ^ 46E98D49BDC5A4604F62AAF76E964838291BFAF4 ^ F1ACC562D96999493EEBD2531A289264C3E1BEF6 ^ 0B261712C3F4D0D74EBDDD052E1A058BCFF412D0 ^ 50446AA7A1A81A97B1DD524AD0DB4D09971D383C ^ E3A51B6AA5AA586803EF2183DECA0CB5CA869B11 ^ C81B52FD60ABEA8CD5E3184E206F693211F008E4 ^ 197270C0DF693622DFE871857A7C87B7BE2E439F ^ 43453DF7620D71CAD56DEF9CEE616AD9E7C73EBA ^ 3E3C6EE1141AB3D7EA5215ACEF4E876EFA89D03B ^ 5773C28260C2B2D325883AE73B04D28BFD2E8884 ^ EB6F26A0E774022773CD86E1C8DFEA461CE6F8F8 ^ 6C26410B11A0CFC97849F6E43E77B8E48D5C5363 ^ F0236CEF2298ED3D86A95E9F5247C17499A772DD ^ 704B5496CE0AFF4289F3D915230F69ADC7A1ED7B ^ B0D4FF6B50F09FBBA19F76693AC9CA87768E2758 ^ 10DE4F687577CCAD9E16AEDC9958021D90DE8726 ^ 785741949059E8508DB8D132A9B053EB4277119A ^ CB041BAF13AD22778A1C73A8AAAB7458B664B1C5 ^ B4B0ADDBEFA078AA497045629840FD965BEEC33D ^ 68F0E43B7DF89F484F3CBD6984C95168142E4A82 ^ D042BE14A23D0CA1A0466179C119F2A959E1E118 ^ DD23CC2824A881FDB6566AE6A57B1A2D1624E895 ^ 15B75E7E13B374039B8C9FB4A1122BB8A22FAD6F ^ 849F0D379A2775CCB5EBB0A88839516F30A665FB ^ 8B4125FF2EBFA9459075459C1EE149D68C4F98F6 ^ 1D632D3EEC63D18243FF48702AB894EA05A1AED3 ^ F2C2E1082004EDCBE3DF96C25D8860C0F5B432BD ^ 4B96C3C284E9E12C3D2F18AB8C8FC6776F30C6DB ^ F40DC8B94D9FE9910117BCD66F3FFB22F6977447 ^ D65D126DF604DE306AEB41A641DE0B214449D69C ^ 90FBEFF058E825EB940122B6D8B7492FC574B32A ^ AE4414AD47216DA0AFD9AD1E22C882F665429C54 ^ 5F9D97E91B7E4810AE765A09803ABFA50B6F64E4 ^ A2D4E6AF7AFD87E303E867D0E03E1945A0F0B72C ^ 14ABF713982D4DC7C1CCFCE7A48680576082DCAC ^ BEB8F77A7D211D9451B698D65FBC0B5E38D26086 ^ B35F660629962D5F1F8529203999FCA0169F2675 ^ 07AC5B04166E739A9FB87FCCA74112AD93A08128 ^ 2D8272C9D620A730561EDFDAF2A129666CEBB5C9 ^ C25C1971EAB264F44CEE1F44614579EE6D8C7858 ^ 76F8234E2F0A533E810545F79AE28A7C46056AF3 ^ 35025EA09EA111E299814FBC958977DDBC3A2387 ^ 0A2EF548A38D84F6A1CBB2AE01D48D296D6CD8FD ^ 6F546DD1623E92DDA185BDA01618DF7E7E7B82F6 ^ A0C1C2AED8C3F436DE200E2A3F4C2A9D2DA8DD7D ^ 8DC10195B967FC7FE57B338494C2C42FB43599D5 ^ 0D9192B27851CAA766D90A5376CE255B2FDE906A ^ 7799450D003824356EDFEE1B408AA59E830175A8 ^ 2EA6F3188D3010EDF4EBB55E009CC4D99296F578 ^ 2A73ACB83FB8E25D65FBC1B8085BE67342F5858E ^ 67F9928A27118ECC38EE231E05977A694AD0F7AA ^ 27E2078CC9FDDF5C5DD6CE629F3EF071B2107936 ^ F50540B4DEE071C64D861872F1E0BC4C7DE75B52 ^ 87DC9AF771F2EE543F96DB0C924AE650A063F854 ^ 76DB885DD797249A4E2F794171DD559FF056A9FB ^ 9AC2E9CD3881BF14D758A7FEBDA81BC9DDD31652 ^ D3D8595D75AF4D1EEEBEA8166CAFB156E827DE90 ^ 5F7D9D9BD0DDC5A2AD4772610FE2A4923A826486 ^ F437BB6CFAA9139A1201FEB58841B18C3809F00E ^ 8C3EB402D92E6543D885A9FDE2FC80B9D4340E8E ^ 134307C50C24BBD7822DBA30F644B874EBB54F0A ^ 24774DA4669C2037F7B2A43BCD1C8D574715F071 ^ 69FEF8FBC9034D05F3C9BD9C663D2198AB48FA30 ^ 0390F1C49421806B19DF1F886902F37088DF77DF ^ DD535B129F482256503AD2744B712BFEB8BF216B ^ ABEC552E41020144EFE06854149BE03F1BD7F6F6 ^ 3FC8C8A14D1452713E76EDD5EF95C239F3F8A4E4 ^ 8861A84429E238D94E75D3CC191FB4D128215F7D ^ DBA6377C376AED4D1E79C198EA864B6E6D90C494 ^ 4E5DBF823DC5BFF56C999A1FD0ABBC51155017D3 ^ 6699420C6FF512BE5CABFE1EBAEFB0AE40CDD902 ^ 77CAE0D7EDFD2D13506D096D66A32B9907AB9B23 ^ F6022F2A1545842915029B344B19F4C69757925D ^ 6ECD085FF34032636E7BE7269D29DA62BC4BFB5B ^ 60CC512BE506BE1A580CEEAD2A009DB8D7A1BBC6 ^ 0F34DFD7EDFA6A5DD132B2EE77B52EEAD98DC701 ^ 1BD542585AB33A0A3694BE45D6C7EEBC266D4806 ^ 1524F20389EBC2D7DE777F96156DF9B2A8652373 ^ 451282E6DA707668886AF7E77DB4C58F73CA6EC2 ^ BB7D59890BC39F7F87D4DD7E2583C737B2B40B86 ^ 255D67E3AF65376A1D71FFCCF505812481AF182B ^ 4D559BC171516F79E22938DE999685F9FF05383D ^ 2F7EB16081B2338D631153D5B70DE67F050E348F ^ 5902CE6CF7700D2E23CEDEE742E273F4A6A39F6D ^ 7D37A7515D1E04D44CA0F314306919C0307FF4AD ^ 18C215A5B8AA9CA5C55DF8BCFC79683E9982B159 ^ 63520C9DD2CF321388DC89CC69D0D9F6772A3553 ^ 5FA13E6697196EBD0E40FEAED4B945CC93375DAD ^ BF8CA60D07D1B69767056B2F80A9AC4B1F9FA99D ^ 6CDD13431EB70D9E346102B708E9F8AB233CF959 ^ 4CB448B4131DEB8F1AC3085765303CF214436A26 ^ 1FDC9CC58A748A9478A9E55C66C6446775382ECD ^ 0EDC5CC7CF8C6CB318616D62CC08CD1449960315 ^ D5D0D540287D21AA519CE90B6E3D81958A2E307D ^ BA5CCD323B987F54E06AE04A09957BC417ADA611 ^ 26846FD68BA956CEB2899DDC18324843DC211485 ^ 12BD70565F701BB35B87364B47F73C93287E7672 ^ C57A0F96959C7DEDD353462099EFE380CB273E90 ^ 9900D5268B99165BE1AA2A6B41B9FB66455B865C ^ D5AC2C2BF36B04EAEF95E8B93958BE28B5A4C836 ^ 82788DAA7F95292B266CA17E86631D866D68FD47 ^ 37B9E638610418C4CE4CF9AAC0D3E64F033D3D74 ^ 9845A156240CE847508A1D3762362FA90216E59D ^ 9E59DC76EA01567183A4B4AD65CD31F169706CA9 ^ B2B4A1500A176C883268447A09DE920F0CF77F76 ^ E14FA11B60B9389D3B9B2C1E7C45931992F666AE ^ 922D169C624E79DABDB79B76E777F6994C339EF9 ^ AE99C2F46A3939CC5EE3F8CF68D6EA486392C23D ^ 154F915F90340CBB03B9514810FD399EED06CE3B ^ C440E1E74C75266822919080966AB74D96FF43E2 ^ 405155FA99EF5E4A0F4E93D107CAEC89A80B94A2 ^ 0AA9625455A0CCDF37D486B4538E790BE407A59C ^ 46D633F7F2EC56496D53138A56D11D9ABDB701E1 ^ 75C1BD5738EB5380E25EC4FCFCC7BB3FD8164460 ^ B618C9E52303919BF762D452F5681D23ABFF23B6 ^ D08BE1F5485939677D294C4198FA15B118938B3F ^ F931441259B793DABAF082D1B0024ACAD3CB48A6 ^ 096E206E3753BBEEC8F0F0D3F97EBF2EB3063B1D ^ 13AA397D03C60AA4414271D33CAC2361C138422B ^ 777E2979834E8C6E89D219E9109F0A2852961EFA ^ 13960A648DB8B7CF541A56B9009A5F7FBCC1ABAB ^ B3447A3C462B53945F8295032FC9A057BC301FB7 ^ 8C42386A2436DE83E1959E92B44EBF61E6C8D093 ^ D9EF91B04DD4371968E1978CBFEDB50C2BABBE67 ^ E84042479D1D669AB5871B71D1342AD6D15105C2 ^ 4ACD112CD8CAC72DF2D4DA76910C2CD3BE1EC25D ^ AA20982E2B138FB2407EF99509075CE8366F10BC ^ 5E3BC535BBFF471686885331CD9831C80FEB18CD ^ 53C55C80D64411221C7311654921523D2BD0E227 ^ 3FB8C850B9BC7A923767D036992AD79ED7F0E1AD ^ AF0BCA4D440D6599BB91396A0823DE64764C2112 ^ 30B13703A702572257D54DC09463768F5AAEF759 ^ 59C44B99EDC297B476402310044554B3F29F9CCF ^ FED078596C584810E5336545F6F6B93027D9CBD6 ^ 6499E70E5455F9C8FFD2D5F600009A43FAE710ED ^ D26C0718A9C8222F30D021E8FA6508935E80BC85 ^ 1F4152447ECB8D7CD725B57B65E30F79B466BBDE ^ 6C4958665DDDFC828C1427E57D23359E9C5D1190 ^ B88EAD843C4897B2A691612B837E5A5D9F58172C ^ A51097DC1883B160AB799D2D103C443336EAC2CA ^ 5DA1B85BBF4F3912C5E964242A61EBE83A3DA5B8 ^ 4E9A45C0410F0211DD4D9123BFB8C29C53A5E03A ^ C2B7C89F7DEA6E5A6CF909388471DEC4CA362255 ^ 4EF3B7E7846115212B3E77C29AACA6198422BEF2 ^ 78C74563BB2CF819F83E73CC00072378C114639F ^ FAF96E836C381EC80FE1EA8AF76E9D8D8AD95FBD ^ 3B30A2BBF84AB70E8220349CBA249DB87FFDCBFF ^ 6CE0CC298D12597F801E0F1BDE66CA9DDF6AE66A ^ 8274B1DB8C0C7390C383C837FDABDEBBEDD1A8C1 ^ D0F90D63ACD0126C84D714AD7C9EB673DFB459B2 ^ D1E63EB5C373C78EDF968E0651DC1171907258F7 ^ 1530DC99565BE2B5AE91D1D70B027EDFD4EC6E93 ^ FEC0946FB9CC04713C67BA36FA36EA9211131281 ^ BD2BA680D2200AFC5CAFB362A5517BE9DAB7E593 ^ 5FB57E1AAD5BD9C1D176E1CA03C1A5A8E33DDE2D ^ F6D5E7B1B28C9070115DB6665309B8DDF5F81281 ^ BFE88F7A0FD5F6A1B26A5E15D0A109A1DA7C1FC1 ^ E5668AA40375C8CA35FB3046EDD8AD9EDBA82FE3 ^ C854D5C5A0A100411FCC9189D6307C47B57228CF ^ 1EE384076308AC6B80FB66856D5FA19952B3D6D5 ^ CAA4DCFEE058D22D726292B2C722D3147F1DCD63 ^ 1887C76092C9275B2DE333014C99FD13E5E533BA ^ AEAC6ACB4561985DCFF6C9696BE836FBF75E24E9 ^ CA46F23773B30BF0ABF5C38EB9D0EE021D713F8C ^ 2EF007988B2161FED07E5181C342E724D3F640A3 ^ F0F1422DFD34EDE00A8B0741F4F395234480FDB8 ^ 2C471BF867F5A02CC241E35D95C97B43D6536E7D ^ D4906C8804B241E28F3F2E6380019FB739EC8503 ^ 632183EEF8C6EC8EAA3016A43E568DC38E29379C ^ 1808120D461A867C90222469985769AF1756EE5B ^ 08C2F97B6FA6E1433DAF56403CDFE8CEECF6BCFE ^ 2767E111977A20D318EAE19D59E1E551A4AA7F1E ^ B1A7158CE56666BCD1FDE7DC87B40C92705BFDE5 ^ 7CE90514AD734390F6FE58BAE8FFCD66391E9595 ^ C57F4C2D8B78DB8464EF1F719B8B1DA270867480 ^ C97938F34C6DF26BFD509658838F7C35FDB0C58B ^ A5CAA6946300B1C4B5F53A69AAAD67961C4C6821 ^ DDF684947B1667A77A22C7DFE8B6A0A8484E2509 ^ 8FB1310F1F215E4EF62C41566C523275BC929670 ^ 1573CC447B398532BFB9A2E5AB3880F23CA7C27D ^ D6E0B674B9E4D283C0AAC355989CC0E8BBF09678 ^ 7D083BB9C3E005B41FE32629F84B9E292D80FC67 ^ D3E2591B7D7CD29E9ACE61DF6019D8787AC93BE6 ^ 7159B10AACA9E7610C7404DE961ABFDB17B89156 ^ B4A0248088E850FFC5CCA99EA2F28ECACBFF1960 ^ CA63F54FDB6C46E877760EF4E50E56F3164A417F ^ C41DF52EB252961619BD4861C4AACCF1AB392B69 ^ FE3EFE453C8705E1CEDD06F15DF5B35A7311DB32 ^ 5E2E8BB04B327E91572992A8A61063F7A76A93FF ^ 8EA0191E8491400038CC5B1416E5A56622EF1E8F ^ 47727D4D7E8D9738608AEEDEB0E12C9F2427EBCB ^ 7340F405BC428DA514E7B2F39728CD77FA2177F9 ^ 5E451C7A51AEBABCEF9FDFBF3538AFECB968872B ^ 528038274803D6DB419F6923993A45C999433336 ^ 281D30FD3C725A4646A6287329140BEA4AC7A5B8 ^ 922A57DBF62C01DA19B89F90F36C433817F089B0 ^ C79AB225BBD03145A981DBE7BF6FDD16A5E95D8A ^ 301B4D0E270F2AEC6E1372560385D37875EB682C ^ 1EF2EC6A3642C7FD61C4F1C3DFC55302535254B7 ^ 1D94ECF29D2310B1A5A2042CFA616BA0D19E7C41 ^ 52DDA9BEEFAAAE667A6D12BE414FAD8619750040 ^ B14486D16D1521D1283698E651A10FC14AFF8996 ^ 4BBFBD0244BFEE440DBEDC8361806CADFF673253 ^ 662E0E466C9D700C50C5F98CD77CFECF8278D708 ^ 1AC5B8197B0689681B0F474832F316CD25147AF3 ^ 8720E012F16588A3C368689113902119C9791FF2 ^ D892C1E257A997A8DF95B229C9D24C99F60EF205 ^ 57F5C45286EC3D29CEC19939C04045D9C38E761E ^ 07151D2EC889D24730AAA5282FA4DFC49A66E439 ^ 6AC94690EA6DB4A8DC982271490EE18282A3B33D ^ 32DD19F12AC0854998C7B14D1D96C15FA8995DBD ^ 7817A25C6CF1EBFAA8DED7A80063D1A299AF8B18 ^ 01C5EAC1830D1F5A7F186E039663CE925FCBACDF ^ B9F32F67FF4937F44094CB4A62BE12474AC3E1AA ^ 05BE2CD6882447472AD2E02B08590EDED62C7638 ^ CEF149F6D6FC8987C3693D5F5CCAC0CDDD3D0787 ^ 6A7CC99DAD86DA9797B1F8336356C9864F279D35 ^ 3A72F8EFE64CF60D49589AB92D48301620CEC0ED ^ F1F5939419E375182A2AA928DAE3CF6C378E4589 ^ 3EC1C1B74B8881F86C1D3EDE42F6689C61132710 ^ 7164A5B4A69A004FD76EA4C6CDFE0273D35CFF71 ^ 224325A309FDF2378C5776B1751BB0694ED30C28 ^ 64E0FECBF5F94517EA9E0F4E1E16FC700EE275B8 ^ 69CDF3321850BB640D5231D3B3458F83738CCE6C ^ 0684349A2ABEC06CE05100EB69D01CD4FB7AB193 ^ 1DFA49225C0FD725046AFCAFED17B1ABA6871FB7 ^ ECF4B1B9C78A802F748D58BF6E27FAF1B274EEC3 ^ A44B67EF91F2AAA9EB2DA8B166A1A316886E8909 ^ CF38B0F7DDD2F72A891B41AD026FCC3282218747 ^ F917033D4494A1CCC8580C1DBED6F28FEB3E2E57 ^ 3C326F550039F815ECF5E236F6DDE5DB0E2E9F65 ^ 7332001002A11FDAF501914A867398625398D5CD ^ DEA189DC41AF695109ADCD93906EB5372B512A57 ^ E0F14BCA9240B27E44647ECEB4A40408E2880DB9 ^ 77545EF84146F952212D9E1FDBAF62243CDA630A ^ D162F654DEB5BB0D54179319D8DF9F1BB6D8A13B ^ 3BF79007252537CC2EB11E148842E7AC443CA91A ^ 6CB2F291C7198C9E4112B991FD4D829DBAD7EFB1 ^ C850258036781C0AE8A083D6A791D3FAEC946C99 ^ DC64C5037BDC93A3D38613D203FB3D7C82A18A24 ^ 620B7714289FD82ABB9FC776B644571F72A9557F ^ 4BEBC1EF44C30B0B033153F883D5C58E4AE6876D ^ E3815A4E6BF3B50EE312E5A795B3E9AA2D7832AD ^ 9CB13D19C64752209D5D4D7033FAF9DE8960C147 ^ 3182B9F03D0ABA3BD91A1EB8CDD0F465FD9CCB51 ^ 73D8E8B9E6A04E88E29797CC5E2F489350D978A7 ^ 732734CCEC18944BCA784B953DCC0E582225AB89 ^ A2152DB03048AE27B47C25DDF99D249504A8ADF1 ^ AB70B32A28D9BFAAE1CA868C4A161B6D4B3A92E5 ^ AB8B90085B47050B87F4BDAFDF971790B7950900 ^ B315A8C87011BACA969A1B79EBAC80A7343742E6 ^ B78A044908CDA9640633DC8BE828E22F90E6D7F3 ^ AC2BC5246C1BD99231CDCCF3CECDEF5688E58D71 ^ 0679F888F8C353B807F544C2379BB5A4AE8EB9A4 ^ 464B5754E3D42864CC0A98B4E696C827E3254317 ^ 7E5385C8A1BFF0FF476905BB6B7515B6D438CC0D ^ 0F5C968CA2FCB4A17E0AF0B94682B3AC347C2D12 ^ 4F5E353500D63C99F58A28F5870064FA278FC7BA ^ E7A104651C4D6DFD0778EC8AC8E4F001BC7B9DD3 ^ 23DCF9A854D1D5B5599B14A0E9A19AB4F2E3BB77 ^ 588E429FA1C3055C4DCC99EE5407A64115B54345 ^ 39215ACE01669CADFB81E9FB085710EB5B97461B ^ 23566449DD29A315D413604A2DBCFAE0D40579A2 ^ 1EA87C13DA38FE4C59691D96AF590EAF3908C0F1 ^ 5A6170FC6BD7E8C01140E16F248C56890B51323A ^ FF328DFB506B72FDB8DF5716E291A1830BC539D4 ^ 7B4DA846F9074254C676F00948BD4C9698148C4D ^ 2AC310393EE1ECC5844A4BEC15A9CFC1B5022294 ^ 3AE36316FA94B369D7320A8B71304CE6490FECCD ^ 7078C7041275BCBE8403DE24D16A646B4462882B ^ 8325A8716A2C879888BA9F674C869B1FF31BF363 ^ 586200B55B5D537B59B5E0BC6FD9BACE1E72C6EE ^ 0B675E7F434756F5E310B80B58F861E789495F5D ^ 749C4C0856CC4629DC397678C0E8BDCBD649A6E2 ^ 25327C66FF46C4466F81EE635E8EC02C5CA60F2A ^ BD9DFB59EB5E53BA6988734FBE0894194A119D33 ^ 3084040E5ECA5E77406B4DF3CB7F324ACC96B506 ^ 1E14A09FEDB61CEBE255B94F533C4018E5AF4BAE ^ C8840C051A204F8A13420CF17FE77EEE2FD7945D ^ 4790265B5231F9A1738CB9F8423BEEF219DF110D ^ 354947C0F2F25EB491D21BD0BD1D809FDD140A66 ^ 23762BF3CDF3F484C70D2003B55E6F447BAF46FA ^ E5BFC99555CED5C1743B152A64AE08C9ED1365D6 ^ 4CB44DC507F716BED4B4CAC742E79E1A2DFA308F ^ 62790EC14E8CFD1A0D6FAF93D7984A1E9416FD5C ^ 5C2D3ED988F5BD9579D2F710D5DD68B11584295C ^ CF8414ED85FA0135E44B37A8F8B40756BAED23DF ^ 03432064C1C05D28393C9AC5878C9A9BAA6E5C7E ^ C37A6D64CF81CDF7DBB1B81509A67A0A1BB5F278 ^ F341D89B75E599048A911D0AE756E0065669B4FB ^ 269E1529285414A74B76586EA4FCECA895C7D1EC ^ FF9BB39F9FEA1EA63D944BF12ADC98D1D4255096 ^ DD114F2DF3D92977F9DB98AEC04F367CFF9FBA2D ^ 69B53BB13375F9E123FC30098CD9EDB3C1A1FDF8 ^ 2A60984DC79682E96C29CC7050E1ACF988D9E4D6 ^ 09AC4CA1A40A7D83A463AF0804C4EDA208E09D36 ^ A2EE2473C270A0637FAAF17DA54237D37E0C6960 ^ B3A7817ADE962DCEEA7FB6F960EBE2BC1F9BCBA7 ^ 85A46CCE01A7968104496225483ECE2C198F2A27 ^ BC028F5ECD8773AE47563F1216E0BC36A9E37E4E ^ C65C40CCC3DD80045D6A4EFF3E9C7D6E4E0E5583 ^ BD9C189A639FD3D70167367DF61F14868CE7E313 ^ C6899A84B8E66548BFB50781632CC3D2D1BE8B9E ^ 92F3C8E436227976F32F005469DE91B2363150DC ^ 7D2A80A5C5CC88988F38334AFFE31C04AA1AFC9C ^ D60FACFA57F663C4A399B1FDDD75973910F27294 ^ CEEB9661BED2E89DDB07A21EEBF590BB1AD644A0 ^ 0465C9DF2E0886AC79F46BBBEB0A243DF7D6BAAA ^ 98073013597B7AE84CB884BD932E20E6CB47709C ^ 3CB4F76B602BF6B58B316A2D8D169D432F02CE23 ^ 5CD4EB05E8612974BD9C3B19E48D192BE8B96A09 ^ BB188D5FDE806BD30648B6058143F1802F15FA10 ^ 84EF1D3DE5C1144C2C928CD4D9070A6E79543417 ^ 73BE2AA66F5FD6BF63273EA136350D29491A3305 ^ 53CF3BB07761910BBB486C3C0C643943D5BF17C3 ^ 9A774BDBD27C3704871B52CD5F7F924C8EE4A67D ^ B106B6582F0F6C9E2EFBC4860CFC7028F2C47F74 ^ FEAFF44298CBB7517B14B81A6AAD501828C773A0 ^ B5BB48BED969F15D162301966C537A81C40CF4B3 ^ 3495D7E36747B824D33465B5DB72D6C623EDA72F ^ D7F49178B43847D9984B923DEAA6DE9571690B92 ^ 3AB7E26BDB0409E55063AFFF456B7A29CF098AF0 ^ 7984E1565BADCD2249EDCA0A3AADB4346104A556 ^ 42DD99B41801B0C347580DF1FDFB2397D55D2A85 ^ 8D59C00401EFB314A0DFA4D82E1D85711C77E246 ^ 50CF74894F7CF5A9F37C37B47327047E910D88A1 ^ 1FC40E2840C4B68F40C205B6BB06C3E106B6B8D8 ^ A49F56DFC293411736F27C19FA2A362A545C761E ^ 221E48845FE8B3D2C79AFED37414C0D732A69F4F ^ AFC12E7BDF9F48FAB1B595FD656776A39F0F6CA8 ^ 5EAA114491E88938276FC3ACCDE659623C024BD7 ^ 5081444C3F81E18114B289020D9AEC75FB205597 ^ D4F69156DE85C61E9B4150AC9F6F6A54F8E193A6 ^ 3D7C7EF4D362DE137AF0625925B36837C1FC7572 ^ 575D772F9C1CBCA8FF38243348E0DFE02643C28C ^ 0C821F27FD82C55CB4D76D386F41DDC92F79493E ^ C3D0101DDF552A11C8E1EE6BFADB72A983F38571 ^ F4D650440127390F3A3C2EE991C185CE7650FAEB ^ 54460FDAFEF3022BC2C7D1D497CBE5CED73624C2 ^ 9B3F7B9D594AAF6A26F5C21BD6E4717F46267418 ^ 14E2B34F0B2C89DAE1732400C02E2CA19A767F8E ^ 1072ABC4DFD2FDC6C114314D3C08457772421713 ^ C9EA4B020C11DEB794D1D05957473A46A906B472 ^ 90BA4272464A020612F0085B7DB9367B7BA8E15E ^ 8713A3997A3CD5DA87E97AB94851B68E748268CF ^ 370358D54C819703E20EF63A2498C8586B48D44E ^ 0DE40249A8B215E98E849008FB7CAE80EC23F4A6 ^ BBDB96306594D13598BB0109258E488D486D98E4 ^ DF7DB9CB2FD8A86854C5DEFCE59C4E2F0245F582 ^ 84DE32ED88B3D2BD5F4E33BA3398CD2EC1E9BDF3 ^ D20967844FED11CA71D28D72B28ACFDB14A7DBB2 ^ B13A0A6A7723BCD9098E2B04FA04320C4A0E605D ^ BE66BE38F97E7DDB02EDC8E0ACE97CDF83F034FE ^ 28ECC25FFB394AA8DE18F8ADE8B3577955346FBB ^ 45068B6A0F61D0AEF708AF7D848683DABE817C2C ^ EAAD829C32C3AD4EAEA8B7E6090A5CF6B2FCAA82 ^ F445FEB22DF5A9E49E2CF7AAD7CC1F5F72F18B77 ^ 73C424FA0B7863F1F170A850F6A0F85C87820841 ^ 71F0155D40CC55F3D64BEA645608FD184E2543F2 ^ 4542FFCF50267B77502D1A0ED0C2A5050CAD5200 ^ FB48F26F320D7A4B803ED459BDF92BC1F8703631 ^ C9F9A37E34BEA6220BEBC167E34B0BAC6B55A6B6 ^ B0C836CC2831FB8BFE5988360CC39FAA6A904A89 ^ B0CF783D84BF5383EF30EF2071E0FBA9ABB553EA ^ 8411C8D1A4FC3F130143DEC5232B59BBDDF11B7C ^ ACB6D9EB22D474CFD5836C8CE22F387E12DC20B7 ^ D582FA3DE1DC425AE6A394FE5AC321DFE96B9305 ^ 15CA32D0E246F395DE22FAF8F0FD90036C4016C8 ^ F1832FEECBFFF1330C7A6AC47D6FC1880E79550D ^ C4846BEA159D1D43427CB5802C46E479F9157392 ^ C84FF09BA6A2EE9BD1972B8C0BF25240F5A7EE72 ^ 4E6B4F363D7FDB4083AA6F5E7979966FB8FF6C5A ^ 7A543B81CB4DC93081D8CB6AED436A31C4018A84 ^ 85990A1C35B86BA244F60BA0EBD6F6E801552FD4 ^ D3E07F5D14AE219D3CB59B034764C40056BA95F4 ^ F4C4DCCC63E8FC5402E93CF50533E51D1BECED43 ^ 3806AFF9AD3859B150F1E2A40FBC047FB624CB14 ^ B51A4E4FA213D22548CFF28323C6679D2693110A ^ A7C70C19BAC1040698C7AE6A23B0688B58405153 ^ E74FD8C457581CD09F75EE3D43485130609FA9B7 ^ 86ED1E49D4CA868934D7C254D3AE0D5BF7323CD7 ^ A16507DABC3A0CF7137150C4E6F88D5AC9A0AA3C ^ DDC76D7BA54354112C2D7D31E1A80F0048551E5E ^ D943F6028146EEB0386BB3084FD354CE86ABCF00 ^ 4ABCAB65C7DAA52BDBD13BCC9098643F5A165329 ^ D75FE22162C538BA1E2687D66E2923CEC7375E01 ^ 1A11A2B12D93FB030B0C3441D7AAC06DAD6FB527 ^ F8F3D414C26D09C6CA1B88BE44BE69AC879D3C5C ^ D2D0BC98795740002B2EB6EA6AECA5559340B54B ^ A8A3838BA45AB6B05D1D464E8681AD61B136B6A5 ^ 5B162923200439D870F57AEC584A67CA2E8939B9 ^ A8FE0B55CFB15D977E871152905D8FDB18AA6B59 ^ 02D5D4928969C7A852B5A8AC772A3D1EB424C9A3 ^ 4ECE08DFF1FDE1258B1BF0423E1E31D83C57557F ^ F701430EF6CB54BF0D138B54FB13A1B586A1CDCC ^ E3242A71106CB77D25A60D164BD17FE07EAC4951 ^ D8B18DE86132672EDB330190BE895E3106F92D2C ^ 8CF05FF1387C61A8CC3724BB1283AAD3E2F85EEF ^ 797B311DC2B5D14B5277E49A38A787D3D6A58C2D ^ 6472BC5881A62BA95651DBB3DFF9B3885949C9B6 ^ 86AED4B53D8617FC135D0E1FCB762271B2545A45 ^ E3C888A1C00301AA7CE203A5590D82C1CE77C6D4 ^ 8A081A7A672F91493AC09D95B29FABD043DA83DD ^ D47F87022DB4FAE551FF3FA09FFF02D92D112527 ^ B2271E377E9B158ACBCA1EDAE0ED6BA4C59CB722 ^ 71EDE0C9488A21E62456D06EE393F390478C3F31 ^ 437A1B709176598020EBA1E92386C3979A18915D ^ E3F4AC4384848071C8A9F9868376D941DEC2A9FB ^ 00444CAF6A3F4210FD97DCB8F10F43B28D890600 ^ 9B6BB350E30CEE209C77A3E20BB6ACE867546313 ^ 935D2688AE2B16B79B517BFB79D48CE7E4F0F4E9 ^ 16B21F19ADE7B6DEE665D45A847491B7F055C46D ^ 853397C3565C807AE72EDFA37F4198E801103FD4 ^ 10992C2FFE5127006BAFB2172359701AB10FA4BE ^ C82D6BA4BA621E36872ACEE4AE3BDF33C2381B07 ^ D7852DBC8FF592E08A1F1EE57A70BEFF327D8EBD ^ CF67308422F072415EFB75B43D5B67C7F5362B0D ^ 30DDF35E1E99243F85311A0994D91B8AA543F729 ^ DB2FE340F62A89400AE4A16B61435204405350D3 ^ 744980FA26DE503743EED298B966ED5FA8471DF6 ^ D2C8B803D3DDB54CDE6464D126CE3009A9F0FB73 ^ 885700ECC04EB97943A9C100EB6EC4ACFE59DF81 ^ 770F9CAC5D4E9C878A6636EB0306EE8DDF0CF915 ^ 03C3F0553D7CF16CFE3D3F01C0A4CE26A914512C ^ 93B304BDB138DB6790DFF8A84FFF3D3506770CDC ^ D5C5FA0488C5A6E14770F216B575997950A94184 ^ 2F695B8EB18C28250D7C8B35BA000042EABDB245 ^ 0353FFA7F7085D3B7888F96B8498486EE7DE16CD ^ 239FE3AAC0D3739F5EEEC82B2BF6F5F47D058548 ^ 16DE8684395CCA8A5DBAC72ECFAFA4BC3DBFC5D6 ^ AEB2BA742708DBC048B01FD77B1560CD3A23E707 ^ FAAE178B97175A7A68E51BD7EEC06234723B670A ^ B3F1311247D920110972772C3DC30F789D3FDBAB ^ 466F682842C07D2C770B41B66A66BE9F6651C046 ^ 39724BD29138F776ED20633B66A3A241FACD817E ^ 5931F19A1985CD5F7171A5D2B81CE1CB3BA8EBBB ^ 27DE5C33A18DF1A731051D6644DE8900E30E242E ^ A4E1C4F20A34C033589ED0985E80168A28C2377A ^ 9BE820B134475CA31513EE1C79D06E299D70E017 ^ 98F396D147EDF3D3079A6B2DCDDE92D48C9CC52B ^ D6108901909418CF7E7AECD9E4D1CA121E992E90 ^ F2E8F0FF1C652356E6056644B81FF8270A07F56A ^ EA1669ED509120F2B42CFA547A3FD6002FFB862D ^ 219BAB55653B03A3CA7886212DF27B23C082B2E0 ^ BBE95F8BBEEB6F9A0062D151A7155630F2010B88 ^ FF6BFC90FE3EAB299892A5D9CA4D17DF2C6C604E ^ 8D0E1DBFCC419AEB1C7827C7649333E34AC7E30C ^ EF3847F7FEA054F0E080836D0F2BFB676E3573EE ^ F60A15E6A28A5CCC9C4EFB1B3107A54C9AAEC26C ^ 76328CDE5EFE6961B2CED4E3457D219229E161F7 ^ FFAF03FB632A042B837F8660412B72B1099394B1 ^ 211BA6675C52CBD9E7F5F5B366A64A2466532AA7 ^ 51E05B7481381358782FDF73CB958E1434CF3330 ^ BB5CEAD1F3B68227CB032B2B8E5B627461071637 ^ 3EBCF1D78998D4D11C094BF28FD522EA9F5A1E37 ^ 3E7186CB1D39C64CEFD28BDA2CCAA073E71A5327 ^ 415B6A0083386054D3B77026A38654D45D3BA106 ^ 2297372256479E31E139AA16E63C27C207519C0C ^ 65A79FC4B322F655ADCF63432D295349FDCA9E7B ^ 2D1130EE6E4156151C637B46527FAC54D9E79DF7 ^ 80E18DE7C798F040C008B3BFE3054261740E1444 ^ 0710A3A300290CC1C3BAB56CF00A682C1B711BB7 ^ C6BE5E337A1A976C253CBF356687F359548B6A3E ^ 3D6E4E514277223BADE6A317C478F17EA6EBC9DC ^ 25C66C904C35EBAD2613A30B73283E0FC23CCC10 ^ 125709FDFD511180B08DB77366DC7E5A2B46F0CB ^ AFB5C53BB272826DB7A1C030B89C7F3AE956F65A ^ D166E71D8142E26E58E0F7A69C50CF19CFE225FC ^ 426007235D8F06FDCFF20CE7FD00E994F2FC422C ^ 8CA2730163EA816BF9B63CC653B443A8E8BD7656 ^ BB2DA623B5FD10032BAFA1A2F9FB1E13F74AC4EB ^ 82238EC3C90BAF3227885BE78534A1B08213660C ^ 64BA275EE9422356EAC19A46A4C5C9BDB4D63C05 ^ 4995323B85FD3879631B439BF4F8D7D39639A7FA ^ 41F95B512991A4E05B219479842285900DF8425E ^ 3CEBE929AC763F2FD85F21354C9158E5169A844E ^ BAD5D53D67CBCD7767B6009546A91D59188DE99D ^ E9C2909F6F0A3079890193C8772E745A317C48B0 ^ BB97E31E9B8EAA8CE758DD775D8326F94720E198 ^ 109471A1C3A427C65C4BBAF8C785DB99C748E5FA ^ 751D9CC64F00176E424A1F331C63EAF2910A75CB ^ 27EC395B07FC740569612741E5CF13A9A6048010 ^ F674BD87556FD0F71D9BF23A0ECCE9F39AC82099 ^ 93B2F9109A25C511865D15E1683C0683555FFC01 ^ SHS Type 2 Hashes EFA3EC89797EE3F1A5BE4B8D34747136CA7DFB99 ^ D146D467E321E4EA4C73E8424029BEA461F3D90B ^ 25ACD32DED334AD20DDCCF01059B6B8B864E8D7A ^ 25416D69665007C3EDD24161F3DF0F6ACBD0E859 ^ 542A29E5C04A5B79AD0986FAD49BE741F09942B9 ^ 5B197E1011286E5C130F9379843DE89776C37C59 ^ 467277EB8887EDE0F2369C6E7D12281EE3B51857 ^ BC1610204E15A37D533B74412683767898B35DFF ^ 3DC7C4726B3EF75AB89193701C990F86AA6DE80F ^ 4AD4348E5022685C70A2B9806698664C281E7123 ^ A33E4996BD9980ED505F8AAAF0F6D64E97D7E619 ^ 06280ACC2D0DA15EAD7C963253349C86A6C3C6C4 ^ 33BE29779F42EE504A3CDAE0422F7B9C5CC994DE ^ 412941272C5CE344AC144B69D4BA5F61F1474F4E ^ C33ECAC1FA74D54685669F8B9F85918471A88D60 ^ C48272E42F921A2749D60418965D8A7CB1C7BF0D ^ 44ABEEAD2C278098062D934460E565ED3C646880 ^ 08DF185007816E3EF01D6226C72B03256478F23F ^ 289E89F8F15DD709701AA22B12C69E8F90C93F1D ^ 5B93CAB369C99B85EEE3130F833B7BB06D4FC041 ^ 7B2872C58FB340C9A1D068B618E4980B04FDFF2D ^ 62783421CF58EA66366ADDCBFA96968FB1369918 ^ C8BD732D0181051698160B2FBC2025476297C96B ^ 038D587CC069C9B89DBC2FE9D86A98C031D340B9 ^ 3059031A68585DA8F09B87B0BE3413987EB390BF ^ 1B74A4A95713083609B27E67140708EDA15F80B1 ^ 6EACEA69922C7ACE38E0560A91DA459C0CC89B55 ^ 60E21F5299EC719D2832A82268B24AF6B2815DEB ^ 3D7D51782A532F4F410AA2AB3DC9178C21A55F0A ^ B2423D96008FB800E5E35E19DA6BEA27487585E0 ^ 5038FE9AEAC82966A4EE5CC69ACC8ACCF55E63DC ^ 90BF0A90F88F5F1DA51E4494E2D5D4C6250D2D4B ^ F858434E0A5FD61A220CC792380801D19E0D9F77 ^ C31E0BB45FF1DC0DE44C77C53C59B15C3BDE9EB4 ^ DF5628CF6445C409B51F46A86488A95DD34A3DA5 ^ 744CDCC9A51B1AD14FAFD673D4104433B7A24739 ^ CEA5E7B91773DFE13649ACA78907769B5BEBCA1F ^ DC23EC1A04F7417D9704B844E9F39F39EAABE6D8 ^ D39DDE97297B7D1C9FFD6B6733349D0B8E802688 ^ 65219E79F5A3C61FC075660258A9C5F13A159271 ^ D2A86164D1366B60F146651464761B01353F9028 ^ 8E3D1E4E0438EABC58AB967B1CDDDAE3CDD9B078 ^ EE9BEEC73D0E760CFD05CF62382A461C7DE3CE2A ^ 5C4FDD604751596BE5419D4AC256C3D982012149 ^ 43ECD0DE83F087815CF257982914611E4BFF698C ^ 1A1BCA41BA127DF4264D3795E2EBCEDCD1BD8EC7 ^ FF82BC6904520E186803FFE861DCE7E566D75F03 ^ 764546FFA014DF8278974BE66D01485251B8B0CF ^ A06BC97DACB07EF207808684978841C425AE1238 ^ 6C7E6E0E89F2A070EDF3C4333353869942F3D883 ^ 572437B2B35C5BA00EBC74521B12D20E6F14ACBC ^ 08703186E74A9397CEBB1B2034A6770995AF3D0F ^ E4F9055356AABA933EEF0C0B07B6FCE90361D208 ^ 2020203EFD4C5FFA02E593B7A658024B33FB368E ^ 2BB2F32D64ADA56A3E53A6D750A05F8D2B5D7A7D ^ C719AEE4708E7A242440C9429B7236DFDEC02B4B ^ 924A26B46649287197E142CB42506C96E309EB26 ^ 0463F94B5452A2D8BA3A0DBFE9C490A371C19975 ^ 9FB2FE5393238EAAF58034BC934B190784A10DD3 ^ AD4A6962A6A59CA32789AC3BBA368583B9122AF4 ^ 2A89459657F9E2685D794E7AEAF30A05B06AA573 ^ 9B65CB91D0A24773AC8675FE9862E28A7B84954F ^ 9CB7CADEDD391A3689B04427B461C4113717B6C8 ^ F1B922D7EC240FC99692EC28C1A6CC7D907B1018 ^ DE301A1413C36A5CB891FBCD9CF9258DF4EF14A4 ^ B330738D2AD53448C287BEEFE5C5583F2B817A03 ^ B80EBE0104A25840CAEF6AD74C4676D524571A29 ^ 3B5CD01661A279BA72DFC1272E683573B4F16DCD ^ 1412D6A2DBBC9D00641A71164A690C640852B56E ^ 0EF514429CAC95CDCBE8A2E60C2AA8B892AC5B33 ^ 5F32CFF3B07D47EC13EB54E7C39E4F5216FDBDC5 ^ B931966169D171DE8F9488E8B5E0960124BC7451 ^ E5034D3A5A573442781EF0C6EEA7BD39FAD0B94A ^ F97CAC5013135944FDF8BDCF02B4CC61241BEA6A ^ FF74C93CF32506B4E17A0B596AB564989F20F1D4 ^ 5CA42E33BCE4301B8FBCE56BFBDB43EF79E956D8 ^ 87F5D981EDFA01A2E9885BD52CC4E649A2330621 ^ 63F43844ECDDF338203DFB116FA79CBAF4E5C92B ^ 92C5E2A5D380D2BB5E19E9E65DC9A77F4B8B25F4 ^ E3D78501969ACDD78A71042E7B0BD0C14882E402 ^ 4E1FD6F5CFE29A0E33248F2E2EFB74E7E0A99765 ^ 5FF5DADC93B2E452A60677C8CD0CBAF7BD4895E4 ^ CA490FAA2D6723F9F682D5C96586460D0C8B2010 ^ 94F099C2FF7DB694FD2DCF5A9A6B06855B2A9948 ^ CF3B1E0DA7BE87180BF1847DEBEC706788C53B8B ^ F85305C4BF149B92068D363EF19B914DB90618DA ^ B4BAFCA3176B80E9800E319FB3BB74E5D65BEB64 ^ 38CCF51915A38559A96E6F3258148D5E63230984 ^ 6FF43B0D25C7171FF178DEAB13D7F488D21C4216 ^ 3E4A034152D86E4568A2197A5328E8E97363287E ^ F231D4C3ABBE0FDF77C71EB2C28E50ACD9584537 ^ 23E1A4F73F288233847E647CF8623289F1F89E55 ^ 726DAEAE724E79232611CBB216B7722594E814FB ^ 0E5FE512B0AF52B4183119508CB01AF5338C63E3 ^ 4A5D3E12EB29B224202C0B319B086535E99F5E32 ^ 363574A910830EDCFDAED1055975F0613D1B5C95 ^ 4820BE6C74AD34D8A43A5DD0130CBDE3F890C53B ^ FEB6E5BF7A66ED9B838A10305F850052DDF9207E ^ D50B331AD6925545264B6614C3B4C39375AB1F65 ^ 36B1BF39BF4AEF05FB054BD02FAD9062D2337239 ^ SHS Type 3 Hashes 9B30CAFDD7F5E525221EC036D55A9C8D78294DBD ^ 9BCA33B3DAD2201D0F1981CCD0AF4874E162A6DB ^ 8B06697E4A75DA5F020CEB860A29040B3DF6EF21 ^ F0D48401AE22498E281CDAAF045FFEBAA87A9776 ^ 6247DF62DF5D4857A795996039B5A6271F7A2031 ^ D98433C3372F1405FCC2475959B9F35DF27D32E9 ^ C4D14B2873B0BDF01CA7C1628EE01D61682CF1C8 ^ C027A9C010F8EBE89FC88C1C9FB68DAB09A0CFCD ^ 4D8D19F35FAECDEB015E116130A0A4C836A42A6A ^ 928E2E95D3F09D8EE63CB8F10296EE6EF7455FFF ^ 55F3E770DCA28CFB711D059174CC7A9EC2B2DD7B ^ 4500987086FD8C275330E0F27E8A3ED8596D01AA ^ 60BC57D16F50E2ADD1724E0C7DDD5E47DDF8E300 ^ 59D174272AE602AC092EE7EF393AC19B87B8E865 ^ 8C25614E6E4D825D6AEDD93A62D1A0458583EE84 ^ 695390D1E57BCC4CDD442879F0978BD823322E5C ^ 6F353EE6B5F4B8272E4A0D3D4BBCC83B1B942516 ^ 4B3F671874220DCCF49B580189E6B13FFF0F531D ^ BC6C473B4824D8E2FA04DDA86A5865D4A36E8E91 ^ 1BFEC269FD18D25DC5C56ACD83810022775F3EC8 ^ 3E9921E2F685413C0AEA64801945B48CB76E195E ^ EEC7221FBAC5F27B56CF68C396B7EBBCAA3C0B05 ^ F86DDD2A8229532C3F183EA9903AD228A2521593 ^ FA17B5DF33E4326BCDCB27F1CE8B83BE8B8EF890 ^ A4AFC0B41D30CE796C2B4B06E368A5D390735889 ^ 745AF12B4EF985E4D2F848D7C7ADB6B32404B6E6 ^ 5CE4B657409033BF67DB7B0CA480EC2ACCA801EC ^ 0B5AABC9D3A8E861103D6B5B9B994F9C743BF058 ^ 86A1198983A73298BF4EB41A61EAAC3E4B06B408 ^ 460A107A6AF329B330DE9425B3077755553AD370 ^ 62C81D06AFE8C8F3E642AD42374FFE486DE86F2F ^ FC1EECA32F7E434BBC74F4360808EDB141087BDC ^ BF494B4E8D3311F167B1EAAE58A3343683F337EE ^ 961247D01E1C4CC0D71307637CD559D530521FD5 ^ B34F846411BE61E15361922E0E2AF83F3F03B291 ^ CD845B240FC2551DCB2CE487646648CF249AE8F0 ^ 5C124B615FAC548DAA35AD0287E032EC77D220BD ^ 3C74771D838CCF7FAE2DAB100CEA7B46BE2FFF3F ^ 62860DB8C0C897C7369A1AB61747B04C0AE9F8A6 ^ C98400CDD7FE71C7B35488C16D3395C04300EDFA ^ 95167E2BBFC0349C0DB7CB7BD2030BC30F9F286A ^ 9F835DBB27076B5F0D8880603F417CE83A0D2242 ^ 08442B715C84B7A8B2C7FFB46010AE56A0C8C05D ^ B7132DBA522C54F42903CAEB705167485AAD30B0 ^ 9E99F03ED08374EFA4F9A26551A909F40BEE503C ^ 999977E6AFFAE0451E93E7F77C7D177DE121402C ^ 30E0BB7F21433A348E3B446F08D80CEAAE06DB71 ^ B3A41EEDF017DA7B20FBD9111BA6E2E59842CED2 ^ 5B9CA331BD03D97E8D057DFD35C9E600F90C57DC ^ 5338A25B31CC9C64552B6F6742F9FEBDC13D9733 ^ 1B3A55BF6FD748B3B650EA5BE839B61530C871C0 ^ 1503F21523CE8BC5A19E6A7F5CB0EC34A7E9F75C ^ 7F6A16B30377D3D0014B0B0B4C8639160C721DDB ^ 8F621F8CFB6AF216746D8B99C913267DB14ADB08 ^ 42E9177C487B4B711A4451C360BD7E2C6DA73446 ^ 5B2497CA6EC2426B12653D711E6BFDBEEFD4A389 ^ 30F4690FD4F09AC8E29B926F64C673539D7FB65D ^ CE12D1AA4961245E606097B672EC3E16103D0D16 ^ 9BE5D693BC0CC56B34B8DDB92FACEC2F8F4B638A ^ D2040005AE230EFDAE95942372607577EFA5DBC2 ^ 8A920F9407C74FA37D9C93C3606B996DB945841D ^ F26915C08DC1D3D31D9CA73F18F04DBB57E8A672 ^ E449381C8148837B9E44251B17825530D8754C94 ^ BD8402B21520E40E31D1EAFD9C99A9E409C3A77D ^ 624CCE538A78CF0FF788B9BE433A008FA7779280 ^ B796B521B90D55396E8EC02AD9B69B7E91093E4C ^ 5C4D584F97C1D8FAF810CEF3A4CA0915FB0B630A ^ A179FEAF341BA97B1D0278822ACCAE5FCF8F4ADE ^ 693DCF85919E06A5423F92780E79C2C0C4528D67 ^ DB94BEADFEA3682051D622519AF9F87BAB28C5F9 ^ 2E20D1925FBD460E7A5E6B48A92964A7DDCB874F ^ 86651FD71862CF72F01F099F68CC164DEF0E9625 ^ D5948BDCA91D6707015C79BBC2BC74C1B60573F5 ^ 8870B8A6884FF54E0E400441FB2EC74F2452F39C ^ 7DF1C3C052E8396D251E9D522C4227344DF92C11 ^ 59A290A0BD41B973DEE35947CB240006DBCEC582 ^ DD0EDB3AA60CDEBB85DC01258B9F49F3A5E83589 ^ FC6794E4B4F2735773A195F9BB2022C70AA4C754 ^ 8BBC40A02D87A8CF14D6CBA0A2C9857D93EFDEFA ^ D28FF6E2366097135EE565F10263E8798140C5DC ^ 2E4289EBE02E75E53B52D6724CDC16B89ECF3DC6 ^ F2E716831CC0CB5CB2A623197D14C2C9FC25A914 ^ 47B926A13D65377A8E2AF27A84E175BE93739E38 ^ D368B8ACC50353EC8070936C73242A2BF6CEC3AA ^ 8556025BED695B975CB924DDFB372F6899A7B09D ^ 9B4ED89E63D17B7210A3FC1BBF0FDA607694F5D9 ^ 0D2221F5CDA184EC7F6CCA29A75F502FCA25673A ^ 3C152CCB811DD9BC16529B23DFA1757D744FE676 ^ 48D1808CD62F868FB6F45560137CFB1DFD856266 ^ 8A3FA42A984C95CA75D6AE51391AAAC0688C2ABD ^ AB570D91E9B6F3F1188DC8639A3B144837EF1ED8 ^ 673F62A7D205D5C90B7454E81A5EDA9A60650D91 ^ D00575E45FA324FA05142359BC3A07C803836EE4 ^ B908BE44A2A66F7370DCC022378A9C2F9BA70B38 ^ 1EF79029F88E7A091D6F2FA2F44A96829C120C62 ^ 491CB2EE0994EE6A4FAC59C4B9FBC9CF8183DE8C ^ CEAAC4E211E7DDDCE3931C47ACA3D626B62E5054 ^ BE2041CB55A4882A8335A46B744ECB8611336F5D ^ E4C0BC6857AFFE0C2B77B38FC01829B44247B6CC ^ 122A6AF11DEB6C3B97E6ADF5E077B5D6363887E3 ^ 1024, is supplied. These can be used to verify the hashing of longer message lengths. For bit oriented testing the messages are from 1025 to 103425 bits long (length=1025+i*1024, where 0<=i<100). For byte oriented testing the messages are from 1032 to 103432 (length=1032+i*1024, where 0<=i<100). Type III Test: Pseudorandomly Generated Messages This test determines whether the implementation can compute message digests for messages that are generated using a given seed. A sequence of 100 message digests is generated using this seed. The digests are generated according to the following pseudocode: procedure MonteCarlo(string SEED) { integer i, j, a; string M; M := SEED; for j = 0 to 99 do { for i = 1 to 50000 do { for a = 1 to (j/4*8 + 24) do M := M || 0; /*0' is the binary zero bit. */ M := M || i; /* Here, the value for i is expressed as a 32-bit word and concatenated with M. The first bit concatenated with M is the most significant bit of this 32-bit word. */ M := SHA(M); } print(M); } } NOTE: In the above procedure, || denotes concatenation. Also, M || i denotes appending the 32-bit word representing the value i, as defined in section 2 of the SHS. Within the procedure, M is a string of variable length. The initial length of 416 bits ensures that the length of M never exceeds 512 bits during execution of the above procedure, and it ensures that messages will be of a byte length. Each element printed should be 160 bits in length. File formats: There are two files included for each test type (bit-oriented and byte-oriented). One file contains the messages and the other file contains the hashes. The message files provided use "compact strings" to store the message values. Compact strings are used to represented the messages in a compact form. A compact string has the form z || b || n(1) || n(2) || ... || n(z) where z>=0 that represents the number of n, b is either 0 or 1, and each n(i) is a decimal integer representing a positive number. The length of the compact string is given by the summation of the n(i). The compact string is interpreted as the representation of the bit string consisting of b repeated n(1) times, followed by 1-b repeated n(2) times, followed by b repeated n(3) times, and so on. Example: M = 5 1 7 13 5 1 2 where z = 5 and b = 1. Then the compact string M represents the bit string 1111111000000000000011111011 where 1 is repeated 7 times, 0 is repeated 13 times, 1 is repeated 5 times, 0 is repeated 1 time, and 1 is repeated 2 times. dbus-1.10.6/test/data/invalid-service-files-system/0000755000175000017500000000000012627367774022161 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in0000644000175000017500000000014512602773110033143 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteNoUser Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ org.freedesktop.DBus.TestSuiteNoService.service.in0000644000175000017500000000011712602773110033545 0ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/invalid-service-files-system[D-BUS Service] Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ User=anyrandomuser dbus-1.10.6/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in0000644000175000017500000000011612602773110033107 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedesktop.DBus.TestSuiteNoExec User=anyrandomuser dbus-1.10.6/test/data/invalid-messages/0000755000175000017500000000000012627367774017706 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/invalid-messages/too-short-dict.message0000644000175000017500000000064212627362361024120 0ustar00smcvsmcv00000000000000# Message with lots of different argument types VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE DICT LENGTH Dict START_LENGTH Dict STRING 'uint32' TYPE UINT32 UINT32 0x8765432 STRING 'uint32' END_LENGTH Dict END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/too-much-header-padding.message0000644000175000017500000000061412627362361025625 0ustar00smcvsmcv00000000000000## has one byte extra header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 BYTE 0 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/too-much-header-padding-by-far.message0000644000175000017500000000064312627362361027005 0ustar00smcvsmcv00000000000000## has one byte extra header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 BYTE 0 ALIGN 8 BYTE 0 ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/too-little-header-padding.message0000644000175000017500000000065212627362361026170 0ustar00smcvsmcv00000000000000## has one byte missing from header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 ## kill a padding byte CHOP 1 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/overlong-name.message0000644000175000017500000000203312627362361024006 0ustar00smcvsmcv00000000000000## a message with too-long name field ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.foo.bar.this.is.really.long 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/not-nul-header-padding.message0000644000175000017500000000070012627362361025462 0ustar00smcvsmcv00000000000000## has one non-nul byte in header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 ## kill a padding byte and replace it CHOP 1 BYTE 'q' END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/no-dot-in-name.message0000644000175000017500000000052012627362361023756 0ustar00smcvsmcv00000000000000## a message with dotless interface ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'NoDotInHere' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/local-namespace.message0000644000175000017500000000062612627362361024267 0ustar00smcvsmcv00000000000000## a message that is in the org.freedesktop.Local. namespace and thus ## invalid ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus.Local' HEADER_FIELD MEMBER TYPE STRING STRING 'Disconnected' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/boolean-has-no-value.message-raw0000644000175000017500000000014612627362361025743 0ustar00smcvsmcv00000000000000lLJUx5"K}KE):|fi7l&tHDv P Hr.tE ZӺdedbus-1.10.6/test/data/invalid-messages/bad-header-field-alignment.message0000644000175000017500000000104412627362361026247 0ustar00smcvsmcv00000000000000## last field incorrectly aligned to 4 bytes ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 4 HEADER_FIELD UNKNOWN TYPE ARRAY TYPE BYTE ALIGN 4 LENGTH ThisByteArray START_LENGTH ThisByteArray BYTE 1 BYTE 2 END_LENGTH ThisByteArray ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/bad-endian.message0000644000175000017500000000050312627362361023217 0ustar00smcvsmcv00000000000000## message with invalid endianness tag BYTE 'i' BYTE 1 BYTE 0 BYTE 0 LENGTH Header LENGTH Body HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/bad-boolean.message0000644000175000017500000000056412627362361023407 0ustar00smcvsmcv00000000000000## a message with an invalid boolean value ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE BOOLEAN BYTE 3 END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/bad-boolean-array.message0000644000175000017500000000063512627362361024522 0ustar00smcvsmcv00000000000000## a message with an invalid boolean array ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE ARRAY TYPE BOOLEAN ALIGN 4 INT32 3 BYTE 0 BYTE 1 BYTE 3 END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/array-with-mixed-types.message0000644000175000017500000000134012627362361025572 0ustar00smcvsmcv00000000000000# Message with an array of array where the child arrays are of # different types VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE ARRAY TYPE ARRAY TYPE UINT32 LENGTH Array START_LENGTH Array ## array of uint32 LENGTH SubArray1 START_LENGTH SubArray1 UINT32 1 UINT32 2 UINT32 3 END_LENGTH SubArray1 ## array of uint32 LENGTH SubArray2 START_LENGTH SubArray2 UINT32 4 UINT32 5 END_LENGTH SubArray2 ## array of boolean LENGTH SubArray3 START_LENGTH SubArray3 BOOLEAN false BOOLEAN true END_LENGTH SubArray3 END_LENGTH Array END_LENGTH Body dbus-1.10.6/test/data/invalid-messages/array-of-nil.message0000644000175000017500000000074012627362361023540 0ustar00smcvsmcv00000000000000# Message with an array of NIL (not allowed) VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' ALIGN 8 END_LENGTH Header START_LENGTH Body TYPE ARRAY TYPE NIL UINT32 5 ## we want it to fail because of type nil, not because the length is no good ## so pad out the message with 5 bytes BYTE 1 BYTE 2 BYTE 3 BYTE 4 BYTE 5 END_LENGTH Body dbus-1.10.6/test/data/invalid-config-files/0000755000175000017500000000000012627367774020444 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/invalid-config-files/truncated-file.conf0000644000175000017500000000054712627362361024212 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo mybususer dbus-1.10.6/test/data/invalid-config-files/circular-3.conf0000644000175000017500000000031312627362361023237 0ustar00smcvsmcv00000000000000 circular-2.conf dbus-1.10.6/test/data/invalid-config-files/circular-2.conf0000644000175000017500000000031312627362361023236 0ustar00smcvsmcv00000000000000 circular-3.conf dbus-1.10.6/test/data/invalid-config-files/circular-1.conf0000644000175000017500000000031312627362361023235 0ustar00smcvsmcv00000000000000 circular-1.conf dbus-1.10.6/test/data/invalid-config-files/badselinux-2.conf0000644000175000017500000000061212627362361023572 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo blah dbus-1.10.6/test/data/invalid-config-files/badselinux-1.conf0000644000175000017500000000062012627362361023570 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo blah dbus-1.10.6/test/data/incomplete-messages/0000755000175000017500000000000012627367774020417 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/incomplete-messages/missing-body.message0000644000175000017500000000046012627362361024354 0ustar00smcvsmcv00000000000000## message that's missing an expected body VALID_HEADER method_call HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' ALIGN 8 END_LENGTH Header ## create the body, then chop it off START_LENGTH Body TYPE INT32 INT32 37 END_LENGTH Body CHOP 8 dbus-1.10.6/test/data/equiv-config-files/0000755000175000017500000000000012627367774020147 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/equiv-config-files/entities/0000755000175000017500000000000012627367774021773 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/equiv-config-files/entities/entities-2.conf0000644000175000017500000000031412627362361024606 0ustar00smcvsmcv00000000000000 entities-1.conf dbus-1.10.6/test/data/equiv-config-files/entities/entities-1.conf0000644000175000017500000000104312627362361024605 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/<bar> tcp:port=1234 basic.d /usr/&share/foo nonexistent.confn dbus-1.10.6/test/data/equiv-config-files/entities/basic.d/0000755000175000017500000000000012627367774023276 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/equiv-config-files/entities/basic.d/basic.conf0000644000175000017500000000072112627362361025211 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf dbus-1.10.6/test/data/equiv-config-files/basic/0000755000175000017500000000000012627367774021230 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/equiv-config-files/basic/basic-2.conf0000644000175000017500000000031112627362361023275 0ustar00smcvsmcv00000000000000 basic-1.conf dbus-1.10.6/test/data/equiv-config-files/basic/basic-1.conf0000644000175000017500000000175712627362361023313 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf 5000 5000 300 5000 6000 50 80 64 64 256 dbus-1.10.6/test/data/equiv-config-files/basic/basic.d/0000755000175000017500000000000012627367774022533 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/equiv-config-files/basic/basic.d/basic.conf0000644000175000017500000000072112627362361024446 0ustar00smcvsmcv00000000000000 mybususer unix:path=/foo/bar tcp:port=1234 basic.d /usr/share/foo nonexistent.conf dbus-1.10.6/test/data/auth/0000755000175000017500000000000012627367774015414 5ustar00smcvsmcv00000000000000dbus-1.10.6/test/data/auth/mechanisms.auth-script0000644000175000017500000000024012627362361021707 0ustar00smcvsmcv00000000000000## this tests that the server sends a list of mechanisms ## in response to blank AUTH SERVER SEND AUTH EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT dbus-1.10.6/test/data/auth/invalid-hex-encoding.auth-script0000644000175000017500000000024312627362361023557 0ustar00smcvsmcv00000000000000## this tests an invalid hex encoding followed by successful authentication SERVER SEND 'AUTH EXTERNAL willy' EXPECT_COMMAND ERROR EXPECT_STATE WAITING_FOR_INPUT dbus-1.10.6/test/data/auth/invalid-command.auth-script0000644000175000017500000000030312627362361022622 0ustar00smcvsmcv00000000000000## this tests that receiving a nonexistent command is handled properly ## by a server SERVER SEND 'NONEXISTENT_COMMAND foo bar baz blah blah' EXPECT_COMMAND ERROR EXPECT_STATE WAITING_FOR_INPUT dbus-1.10.6/test/data/auth/invalid-command-client.auth-script0000644000175000017500000000032712627362361024104 0ustar00smcvsmcv00000000000000## this tests that receiving a nonexistent command is handled properly ## by a client CLIENT EXPECT_COMMAND AUTH SEND 'NONEXISTENT_COMMAND foo bar baz blah blah' EXPECT_COMMAND ERROR EXPECT_STATE WAITING_FOR_INPUT dbus-1.10.6/test/data/auth/fallback.auth-script0000644000175000017500000000066412627362361021331 0ustar00smcvsmcv00000000000000## this tests that a client can fallback to a secondary auth mech CLIENT ## Will try EXTERNAL by default first without first calling AUTH alone. EXPECT_COMMAND AUTH SEND 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 DBUS_TEST_NONEXISTENT_MECH' ## And this time we get DBUS_COOKIE_SHA1 EXPECT_COMMAND AUTH ## of course real DBUS_COOKIE_SHA1 would not send this here... SEND 'OK 1234deadbeef' EXPECT_COMMAND BEGIN EXPECT_STATE AUTHENTICATED dbus-1.10.6/test/data/auth/fail-after-n-attempts.auth-script0000644000175000017500000000116112627362361023667 0ustar00smcvsmcv00000000000000## this tests that after retrying too often we fail SERVER NO_CREDENTIALS # 1 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT # 2 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT # 3 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT # 4 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT # 5 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT # 6 SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE NEED_DISCONNECT dbus-1.10.6/test/data/auth/extra-bytes.auth-script0000644000175000017500000000042012627362361022027 0ustar00smcvsmcv00000000000000## this tests that we have the expected extra bytes at the end SERVER SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN\r\nHello' EXPECT_STATE AUTHENTICATED_WITH_UNUSED_BYTES EXPECT_UNUSED 'Hello\r\n' EXPECT_STATE AUTHENTICATED dbus-1.10.6/test/data/auth/external-successful.auth-script0000644000175000017500000000053212627362361023563 0ustar00smcvsmcv00000000000000## this tests a successful auth of type EXTERNAL SERVER ## verify that prior to doing anything, we haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN' EXPECT_STATE AUTHENTICATED ## verify that we now have some credentials EXPECT_HAVE_SOME_CREDENTIALS dbus-1.10.6/test/data/auth/external-silly.auth-script0000644000175000017500000000057012627362361022542 0ustar00smcvsmcv00000000000000## this tests we can't auth if socket reports silly credentials but we ask for our own uid SERVER ## verify that prior to doing anything, we haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS SILLY_CREDENTIALS SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT ## verify that we still haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS dbus-1.10.6/test/data/auth/external-root.auth-script0000644000175000017500000000036512627362361022373 0ustar00smcvsmcv00000000000000## this tests we can auth EXTERNAL as ourselves, with root credentials UNIX_ONLY SERVER ROOT_CREDENTIALS ## 30 is ASCII '0' in hex SEND 'AUTH EXTERNAL 30' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN' EXPECT_STATE AUTHENTICATED dbus-1.10.6/test/data/auth/external-failed.auth-script0000644000175000017500000000054012627362361022627 0ustar00smcvsmcv00000000000000## this tests that auth of type EXTERNAL without credentials will fail SERVER NO_CREDENTIALS ## verify that prior to doing anything, we haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT ## verify that we still haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS dbus-1.10.6/test/data/auth/client-out-of-mechanisms.auth-script0000644000175000017500000000025512627362361024400 0ustar00smcvsmcv00000000000000## this tests that tests that the client disconnects when it's out of ## known mechanisms CLIENT EXPECT_COMMAND AUTH SEND 'REJECTED BONGO_MD5' EXPECT_STATE NEED_DISCONNECT dbus-1.10.6/test/data/auth/cancel.auth-script0000644000175000017500000000054212627362361021012 0ustar00smcvsmcv00000000000000## this tests canceling EXTERNAL SERVER SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'CANCEL' EXPECT_COMMAND REJECTED EXPECT_STATE WAITING_FOR_INPUT ## now start over and see if it works SEND 'AUTH EXTERNAL USERID_HEX' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN' EXPECT_STATE AUTHENTICATED dbus-1.10.6/test/data/auth/anonymous-server-successful.auth-script0000644000175000017500000000056512627362361025303 0ustar00smcvsmcv00000000000000## this tests the server side in a successful auth of type ANONYMOUS SERVER ## verify that prior to doing anything, we haven't authed as anyone EXPECT_HAVE_NO_CREDENTIALS SEND 'AUTH ANONYMOUS 442d42757320312e312e31' EXPECT_COMMAND OK EXPECT_STATE WAITING_FOR_INPUT SEND 'BEGIN' EXPECT_STATE AUTHENTICATED ## verify that we are still anonymous EXPECT_HAVE_NO_CREDENTIALS dbus-1.10.6/test/data/auth/anonymous-client-successful.auth-script0000644000175000017500000000062412627362361025247 0ustar00smcvsmcv00000000000000## this tests that a client can login anonymously CLIENT ## Reject whatever mechanism the client picks first EXPECT_COMMAND AUTH SEND 'REJECTED DBUS_TEST_NONEXISTENT_MECH1 ANONYMOUS DBUS_TEST_NONEXISTENT_MECH2' ## And this time we get ANONYMOUS EXPECT_COMMAND AUTH ## of course real DBUS_COOKIE_SHA1 would not send this here... SEND 'OK 1234deadbeef' EXPECT_COMMAND BEGIN EXPECT_STATE AUTHENTICATED dbus-1.10.6/dbus/0000755000175000017500000000000012627367774013520 5ustar00smcvsmcv00000000000000dbus-1.10.6/dbus/dbus-test-main.c0000644000175000017500000000322012627362053016476 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-test.c Program to run all tests * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-types.h" #include "dbus-test.h" #include #include #if HAVE_LOCALE_H #include #endif #ifdef DBUS_UNIX # include #endif int main (int argc, char **argv) { const char *test_data_dir; const char *specific_test; #ifdef DBUS_UNIX /* close any inherited fds so dbus-spawn's check for close-on-exec works */ _dbus_close_all (); #endif #if HAVE_SETLOCALE setlocale(LC_ALL, ""); #endif if (argc > 1) test_data_dir = argv[1]; else test_data_dir = NULL; if (argc > 2) specific_test = argv[2]; else specific_test = NULL; dbus_internal_do_not_use_run_tests (test_data_dir, specific_test); return 0; } dbus-1.10.6/dbus/dbus-test.h0000644000175000017500000001075012602773110015560 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-test.h Declarations of test functions. * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TEST_H #define DBUS_TEST_H #include #include #include /* Only things that are in libdbus-1.la and used from libdbus-internal.la * need to have DBUS_PRIVATE_EXPORT. If you get * * warning: 'foo' redeclared without dllimport attribute: previous * dllimport ignored [-Wattributes] * * then you have added too many. */ DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_marshal_test (void); dbus_bool_t _dbus_marshal_recursive_test (void); dbus_bool_t _dbus_marshal_byteswap_test (void); dbus_bool_t _dbus_marshal_validate_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_misc_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_signature_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_mem_pool_test (void); dbus_bool_t _dbus_string_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_address_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_server_test (void); dbus_bool_t _dbus_message_test (const char *test_data_dir); dbus_bool_t _dbus_auth_test (const char *test_data_dir); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_sha_test (const char *test_data_dir); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_keyring_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_data_slot_test (void); dbus_bool_t _dbus_sysdeps_test (void); dbus_bool_t _dbus_spawn_test (const char *test_data_dir); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_userdb_test (const char *test_data_dir); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_transport_unix_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_memory_test (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_object_tree_test (void); dbus_bool_t _dbus_credentials_test (const char *test_data_dir); void dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *specific_test); dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename, DBusValidity expected_validity); dbus_bool_t dbus_internal_do_not_use_try_message_data (const DBusString *data, DBusValidity expected_validity); dbus_bool_t dbus_internal_do_not_use_load_message_file (const DBusString *filename, DBusString *data); /* returns FALSE on fatal failure */ typedef dbus_bool_t (* DBusForeachMessageFileFunc) (const DBusString *filename, DBusValidity expected_validity, void *data); dbus_bool_t dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir, DBusForeachMessageFileFunc func, void *user_data); dbus_bool_t dbus_internal_do_not_use_generate_bodies (int sequence, int byte_order, DBusString *signature, DBusString *body); #endif /* DBUS_TEST_H */ dbus-1.10.6/dbus/dbus-test.c0000644000175000017500000001167212602773110015557 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-test.c Program to run all tests * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-test.h" #include "dbus-sysdeps.h" #include "dbus-internals.h" #include #include #ifdef DBUS_ENABLE_EMBEDDED_TESTS static void die (const char *failure) { fprintf (stderr, "Unit test failed: %s\n", failure); exit (1); } static void check_memleaks (void) { dbus_shutdown (); printf ("%s: checking for memleaks\n", "test-dbus"); if (_dbus_get_malloc_blocks_outstanding () != 0) { _dbus_warn ("%d dbus_malloc blocks were not freed\n", _dbus_get_malloc_blocks_outstanding ()); die ("memleaks"); } } typedef dbus_bool_t (*TestFunc)(void); typedef dbus_bool_t (*TestDataFunc)(const char *data); static void run_test (const char *test_name, const char *specific_test, TestFunc test) { if (!specific_test || strcmp (specific_test, test_name) == 0) { printf ("%s: running %s tests\n", "test-dbus", test_name); if (!test ()) die (test_name); check_memleaks (); } } static void run_data_test (const char *test_name, const char *specific_test, TestDataFunc test, const char *test_data_dir) { if (!specific_test || strcmp (specific_test, test_name) == 0) { printf ("%s: running %s tests\n", "test-dbus", test_name); if (!test (test_data_dir)) die (test_name); check_memleaks (); } } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** * An exported symbol to be run in order to execute * unit tests. Should not be used by * any app other than our test app, this symbol * won't exist in some builds of the library. * (with --enable-tests=no) * * @param test_data_dir the directory with test data (test/data normally) * @param specific_test run specific test or #NULL to run all tests */ void dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *specific_test) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (!_dbus_threads_init_debug ()) die ("debug threads init"); if (test_data_dir == NULL) test_data_dir = _dbus_getenv ("DBUS_TEST_DATA"); if (test_data_dir != NULL) printf ("Test data in %s\n", test_data_dir); else printf ("No test data!\n"); run_test ("string", specific_test, _dbus_string_test); run_test ("sysdeps", specific_test, _dbus_sysdeps_test); run_test ("data-slot", specific_test, _dbus_data_slot_test); run_test ("misc", specific_test, _dbus_misc_test); run_test ("address", specific_test, _dbus_address_test); run_test ("server", specific_test, _dbus_server_test); run_test ("object-tree", specific_test, _dbus_object_tree_test); run_test ("signature", specific_test, _dbus_signature_test); run_test ("marshalling", specific_test, _dbus_marshal_test); run_test ("marshal-recursive", specific_test, _dbus_marshal_recursive_test); run_test ("byteswap", specific_test, _dbus_marshal_byteswap_test); run_test ("memory", specific_test, _dbus_memory_test); #if 1 run_test ("mem-pool", specific_test, _dbus_mem_pool_test); #endif run_test ("list", specific_test, _dbus_list_test); run_test ("marshal-validate", specific_test, _dbus_marshal_validate_test); run_data_test ("message", specific_test, _dbus_message_test, test_data_dir); run_test ("hash", specific_test, _dbus_hash_test); #if !defined(DBUS_WINCE) run_data_test ("spawn", specific_test, _dbus_spawn_test, test_data_dir); #endif run_data_test ("credentials", specific_test, _dbus_credentials_test, test_data_dir); #ifdef DBUS_UNIX run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir); run_test ("transport-unix", specific_test, _dbus_transport_unix_test); #endif run_test ("keyring", specific_test, _dbus_keyring_test); run_data_test ("sha", specific_test, _dbus_sha_test, test_data_dir); run_data_test ("auth", specific_test, _dbus_auth_test, test_data_dir); printf ("%s: completed successfully\n", "test-dbus"); #else printf ("Not compiled with unit tests, not running any\n"); #endif } dbus-1.10.6/dbus/dbus-sysdeps-util.c0000644000175000017500000001233212602773110017237 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-util.c Tests for dbus-sysdeps.h API * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-sysdeps.h" #include "dbus-internals.h" #include "dbus-string.h" #include "dbus-test.h" #include #ifdef DBUS_WIN /* do nothing, it's in stdlib.h */ #elif (defined __APPLE__) # include # define environ (*_NSGetEnviron()) #else extern char **environ; #endif /** * Gets a #NULL-terminated list of key=value pairs from the * environment. Use dbus_free_string_array to free it. * * @returns the environment or #NULL on OOM */ char ** _dbus_get_environment (void) { int i, length; char **environment; _dbus_assert (environ != NULL); for (length = 0; environ[length] != NULL; length++); /* Add one for NULL */ length++; environment = dbus_new0 (char *, length); if (environment == NULL) return NULL; for (i = 0; environ[i] != NULL; i++) { environment[i] = _dbus_strdup (environ[i]); if (environment[i] == NULL) break; } if (environ[i] != NULL) { dbus_free_string_array (environment); environment = NULL; } return environment; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS static void check_dirname (const char *filename, const char *dirname) { DBusString f, d; _dbus_string_init_const (&f, filename); if (!_dbus_string_init (&d)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_get_dirname (&f, &d)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_equal_c_str (&d, dirname)) { _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n", filename, _dbus_string_get_const_data (&d), dirname); exit (1); } _dbus_string_free (&d); } static void check_path_absolute (const char *path, dbus_bool_t expected) { DBusString p; _dbus_string_init_const (&p, path); if (_dbus_path_is_absolute (&p) != expected) { _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n", path, expected, _dbus_path_is_absolute (&p)); exit (1); } } /** * Unit test for dbus-sysdeps.c. * * @returns #TRUE on success. */ dbus_bool_t _dbus_sysdeps_test (void) { #ifdef DBUS_WIN check_dirname ("foo\\bar", "foo"); check_dirname ("foo\\\\bar", "foo"); check_dirname ("foo/\\/bar", "foo"); check_dirname ("foo\\bar/", "foo"); check_dirname ("foo//bar\\", "foo"); check_dirname ("foo\\bar/", "foo"); check_dirname ("foo/bar\\\\", "foo"); check_dirname ("\\foo", "\\"); check_dirname ("\\\\foo", "\\"); check_dirname ("\\", "\\"); check_dirname ("\\\\", "\\"); check_dirname ("\\/", "\\"); check_dirname ("/\\/", "/"); check_dirname ("c:\\foo\\bar", "c:\\foo"); check_dirname ("c:\\foo", "c:\\"); check_dirname ("c:/foo", "c:/"); check_dirname ("c:\\", "c:\\"); check_dirname ("c:/", "c:/"); check_dirname ("", "."); #else check_dirname ("foo", "."); check_dirname ("foo/bar", "foo"); check_dirname ("foo//bar", "foo"); check_dirname ("foo///bar", "foo"); check_dirname ("foo/bar/", "foo"); check_dirname ("foo//bar/", "foo"); check_dirname ("foo///bar/", "foo"); check_dirname ("foo/bar//", "foo"); check_dirname ("foo//bar////", "foo"); check_dirname ("foo///bar///////", "foo"); check_dirname ("/foo", "/"); check_dirname ("////foo", "/"); check_dirname ("/foo/bar", "/foo"); check_dirname ("/foo//bar", "/foo"); check_dirname ("/foo///bar", "/foo"); check_dirname ("/", "/"); check_dirname ("///", "/"); check_dirname ("", "."); #endif #ifdef DBUS_WIN check_path_absolute ("c:/", TRUE); check_path_absolute ("c:/foo", TRUE); check_path_absolute ("", FALSE); check_path_absolute ("foo", FALSE); check_path_absolute ("foo/bar", FALSE); check_path_absolute ("", FALSE); check_path_absolute ("foo\\bar", FALSE); check_path_absolute ("c:\\", TRUE); check_path_absolute ("c:\\foo", TRUE); check_path_absolute ("c:", TRUE); check_path_absolute ("c:\\foo\\bar", TRUE); check_path_absolute ("\\", TRUE); check_path_absolute ("/", TRUE); #else check_path_absolute ("/", TRUE); check_path_absolute ("/foo", TRUE); check_path_absolute ("", FALSE); check_path_absolute ("foo", FALSE); check_path_absolute ("foo/bar", FALSE); #endif return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-string-util.c0000644000175000017500000007546412624705346017104 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. * Copyright (C) 2006 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-string.h" #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 #include "dbus-string-private.h" /** * @addtogroup DBusString * @{ */ /** * Returns whether a string ends with the given suffix * * @todo memcmp might make this faster. * * @param a the string * @param c_str the C-style string * @returns #TRUE if the string ends with the suffix */ dbus_bool_t _dbus_string_ends_with_c_str (const DBusString *a, const char *c_str) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; unsigned long c_str_len; const DBusRealString *real_a = (const DBusRealString*) a; DBUS_GENERIC_STRING_PREAMBLE (real_a); _dbus_assert (c_str != NULL); c_str_len = strlen (c_str); if (((unsigned long)real_a->len) < c_str_len) return FALSE; ap = real_a->str + (real_a->len - c_str_len); bp = (const unsigned char*) c_str; a_end = real_a->str + real_a->len; while (ap != a_end) { if (*ap != *bp) return FALSE; ++ap; ++bp; } _dbus_assert (*ap == '\0'); _dbus_assert (*bp == '\0'); return TRUE; } /** * Find the given byte scanning backward from the given start. * Sets *found to -1 if the byte is not found. * * @param str the string * @param start the place to start scanning (will not find the byte at this point) * @param byte the byte to find * @param found return location for where it was found * @returns #TRUE if found */ dbus_bool_t _dbus_string_find_byte_backward (const DBusString *str, int start, unsigned char byte, int *found) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); _dbus_assert (found != NULL); i = start - 1; while (i >= 0) { if (real->str[i] == byte) break; --i; } if (found) *found = i; return i >= 0; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include static void test_hex_roundtrip (const unsigned char *data, int len) { DBusString orig; DBusString encoded; DBusString decoded; int end; if (len < 0) len = strlen (data); if (!_dbus_string_init (&orig)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_init (&encoded)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_init (&decoded)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_append_len (&orig, data, len)) _dbus_assert_not_reached ("couldn't append orig data"); if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0)) _dbus_assert_not_reached ("could not encode"); if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0)) _dbus_assert_not_reached ("could not decode"); _dbus_assert (_dbus_string_get_length (&encoded) == end); if (!_dbus_string_equal (&orig, &decoded)) { const char *s; printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n", _dbus_string_get_length (&orig), _dbus_string_get_length (&encoded), _dbus_string_get_length (&decoded)); printf ("Original: %s\n", data); s = _dbus_string_get_const_data (&decoded); printf ("Decoded: %s\n", s); _dbus_assert_not_reached ("original string not the same as string decoded from hex"); } _dbus_string_free (&orig); _dbus_string_free (&encoded); _dbus_string_free (&decoded); } typedef void (* TestRoundtripFunc) (const unsigned char *data, int len); static void test_roundtrips (TestRoundtripFunc func) { (* func) ("Hello this is a string\n", -1); (* func) ("Hello this is a string\n1", -1); (* func) ("Hello this is a string\n12", -1); (* func) ("Hello this is a string\n123", -1); (* func) ("Hello this is a string\n1234", -1); (* func) ("Hello this is a string\n12345", -1); (* func) ("", 0); (* func) ("1", 1); (* func) ("12", 2); (* func) ("123", 3); (* func) ("1234", 4); (* func) ("12345", 5); (* func) ("", 1); (* func) ("1", 2); (* func) ("12", 3); (* func) ("123", 4); (* func) ("1234", 5); (* func) ("12345", 6); { unsigned char buf[512]; int i; i = 0; while (i < _DBUS_N_ELEMENTS (buf)) { buf[i] = i; ++i; } i = 0; while (i < _DBUS_N_ELEMENTS (buf)) { (* func) (buf, i); ++i; } } } /** * @ingroup DBusStringInternals * Unit test for DBusString. * * @todo Need to write tests for _dbus_string_copy() and * _dbus_string_move() moving to/from each of start/middle/end of a * string. Also need tests for _dbus_string_move_len () * * @returns #TRUE on success. */ dbus_bool_t _dbus_string_test (void) { DBusString str; DBusString other; int i, a, end; long v; int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 }; char *s; /* Test shortening and setting length */ i = 0; while (i < _DBUS_N_ELEMENTS (lens)) { int j; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_set_length (&str, lens[i])) _dbus_assert_not_reached ("failed to set string length"); j = lens[i]; while (j > 0) { _dbus_assert (_dbus_string_get_length (&str) == j); if (j > 0) { _dbus_string_shorten (&str, 1); _dbus_assert (_dbus_string_get_length (&str) == (j - 1)); } --j; } _dbus_string_free (&str); ++i; } /* Test equality */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("oom"); _dbus_string_init_const (&other, "H"); _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0)); _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1)); _dbus_string_init_const (&other, "Hello"); _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0)); _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1)); _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2)); _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3)); _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4)); _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5)); _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0)); _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1)); _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2)); _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3)); _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4)); _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5)); _dbus_string_init_const (&other, "World"); _dbus_assert (_dbus_string_equal_substring (&str, 6, 5, &other, 0)); _dbus_assert (_dbus_string_equal_substring (&str, 7, 4, &other, 1)); _dbus_assert (_dbus_string_equal_substring (&str, 8, 3, &other, 2)); _dbus_assert (_dbus_string_equal_substring (&str, 9, 2, &other, 3)); _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4)); _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5)); _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6)); _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7)); _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8)); _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9)); _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10)); _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11)); _dbus_string_free (&str); /* Test appending data */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); i = 0; while (i < 10) { if (!_dbus_string_append (&str, "a")) _dbus_assert_not_reached ("failed to append string to string\n"); _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1); if (!_dbus_string_append_byte (&str, 'b')) _dbus_assert_not_reached ("failed to append byte to string\n"); _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2); ++i; } _dbus_string_free (&str); /* Check steal_data */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); i = _dbus_string_get_length (&str); if (!_dbus_string_steal_data (&str, &s)) _dbus_assert_not_reached ("failed to steal data"); _dbus_assert (_dbus_string_get_length (&str) == 0); _dbus_assert (((int)strlen (s)) == i); dbus_free (s); /* Check move */ if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); i = _dbus_string_get_length (&str); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_move (&str, 0, &other, 0)) _dbus_assert_not_reached ("could not move"); _dbus_assert (_dbus_string_get_length (&str) == 0); _dbus_assert (_dbus_string_get_length (&other) == i); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other))) _dbus_assert_not_reached ("could not move"); _dbus_assert (_dbus_string_get_length (&str) == 0); _dbus_assert (_dbus_string_get_length (&other) == i * 2); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2)) _dbus_assert_not_reached ("could not move"); _dbus_assert (_dbus_string_get_length (&str) == 0); _dbus_assert (_dbus_string_get_length (&other) == i * 3); _dbus_string_free (&other); /* Check copy */ if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); i = _dbus_string_get_length (&str); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_copy (&str, 0, &other, 0)) _dbus_assert_not_reached ("could not copy"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i); if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other))) _dbus_assert_not_reached ("could not copy"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i * 2); _dbus_assert (_dbus_string_equal_c_str (&other, "Hello WorldHello World")); if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2)) _dbus_assert_not_reached ("could not copy"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i * 3); _dbus_assert (_dbus_string_equal_c_str (&other, "Hello WorldHello WorldHello World")); _dbus_string_free (&str); _dbus_string_free (&other); /* Check replace */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); i = _dbus_string_get_length (&str); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), &other, 0, _dbus_string_get_length (&other))) _dbus_assert_not_reached ("could not replace"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i); _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World")); if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), &other, 5, 1)) _dbus_assert_not_reached ("could not replace center space"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); _dbus_assert (_dbus_string_equal_c_str (&other, "HelloHello WorldWorld")); if (!_dbus_string_replace_len (&str, 1, 1, &other, _dbus_string_get_length (&other) - 1, 1)) _dbus_assert_not_reached ("could not replace end character"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); _dbus_assert (_dbus_string_equal_c_str (&other, "HelloHello WorldWorle")); _dbus_string_free (&str); _dbus_string_free (&other); /* Different tests are provided because different behaviours are * implemented in _dbus_string_replace_len() in function of replacing and * replaced lengths */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append (&str, "Hello World")) _dbus_assert_not_reached ("could not append to string"); i = _dbus_string_get_length (&str); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_append (&other, "Foo String")) _dbus_assert_not_reached ("could not append to string"); a = _dbus_string_get_length (&other); if (!_dbus_string_replace_len (&str, 0, 6, &other, 4, 0)) _dbus_assert_not_reached ("could not replace 0 length"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 6); _dbus_assert (_dbus_string_equal_c_str (&other, "Foo Hello String")); if (!_dbus_string_replace_len (&str, 5, 6, &other, _dbus_string_get_length (&other), 0)) _dbus_assert_not_reached ("could not replace at the end"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6); _dbus_assert (_dbus_string_equal_c_str (&other, "Foo Hello String World")); if (!_dbus_string_replace_len (&str, 0, 5, &other, _dbus_string_get_length (&other) - 5, 5)) _dbus_assert_not_reached ("could not replace same length"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6); _dbus_assert (_dbus_string_equal_c_str (&other, "Foo Hello String Hello")); if (!_dbus_string_replace_len (&str, 6, 5, &other, 4, 12)) _dbus_assert_not_reached ("could not replace with shorter string"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 5); _dbus_assert (_dbus_string_equal_c_str (&other, "Foo World Hello")); if (!_dbus_string_replace_len (&str, 0, 1, &other, 0, 3)) _dbus_assert_not_reached ("could not replace at the beginning"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 3); _dbus_assert (_dbus_string_equal_c_str (&other, "H World Hello")); if (!_dbus_string_replace_len (&str, 6, 5, &other, _dbus_string_get_length (&other) - 5, 5)) _dbus_assert_not_reached ("could not replace same length"); _dbus_assert (_dbus_string_get_length (&str) == i); _dbus_assert (_dbus_string_get_length (&other) == a + 3); _dbus_assert (_dbus_string_equal_c_str (&other, "H World World")); _dbus_string_free (&str); _dbus_string_free (&other); /* Check insert/set/get byte */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append (&str, "Hello")) _dbus_assert_not_reached ("failed to append Hello"); _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H'); _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e'); _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l'); _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l'); _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o'); _dbus_string_set_byte (&str, 1, 'q'); _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q'); if (!_dbus_string_insert_bytes (&str, 0, 1, 255)) _dbus_assert_not_reached ("can't insert byte"); if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z')) _dbus_assert_not_reached ("can't insert byte"); if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W')) _dbus_assert_not_reached ("can't insert byte"); _dbus_assert (_dbus_string_get_byte (&str, 0) == 255); _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H'); _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z'); _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z'); _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z'); _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z'); _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q'); _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l'); _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l'); _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o'); _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W'); _dbus_string_free (&str); /* Check append/parse int/double */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append_int (&str, 27)) _dbus_assert_not_reached ("failed to append int"); i = _dbus_string_get_length (&str); if (!_dbus_string_parse_int (&str, 0, &v, &end)) _dbus_assert_not_reached ("failed to parse int"); _dbus_assert (v == 27); _dbus_assert (end == i); _dbus_string_free (&str); /* Test find */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); if (!_dbus_string_append (&str, "Hello")) _dbus_assert_not_reached ("couldn't append to string"); if (!_dbus_string_find (&str, 0, "He", &i)) _dbus_assert_not_reached ("didn't find 'He'"); _dbus_assert (i == 0); if (!_dbus_string_find (&str, 0, "Hello", &i)) _dbus_assert_not_reached ("didn't find 'Hello'"); _dbus_assert (i == 0); if (!_dbus_string_find (&str, 0, "ello", &i)) _dbus_assert_not_reached ("didn't find 'ello'"); _dbus_assert (i == 1); if (!_dbus_string_find (&str, 0, "lo", &i)) _dbus_assert_not_reached ("didn't find 'lo'"); _dbus_assert (i == 3); if (!_dbus_string_find (&str, 2, "lo", &i)) _dbus_assert_not_reached ("didn't find 'lo'"); _dbus_assert (i == 3); if (_dbus_string_find (&str, 4, "lo", &i)) _dbus_assert_not_reached ("did find 'lo'"); if (!_dbus_string_find (&str, 0, "l", &i)) _dbus_assert_not_reached ("didn't find 'l'"); _dbus_assert (i == 2); if (!_dbus_string_find (&str, 0, "H", &i)) _dbus_assert_not_reached ("didn't find 'H'"); _dbus_assert (i == 0); if (!_dbus_string_find (&str, 0, "", &i)) _dbus_assert_not_reached ("didn't find ''"); _dbus_assert (i == 0); if (_dbus_string_find (&str, 0, "Hello!", NULL)) _dbus_assert_not_reached ("Did find 'Hello!'"); if (_dbus_string_find (&str, 0, "Oh, Hello", NULL)) _dbus_assert_not_reached ("Did find 'Oh, Hello'"); if (_dbus_string_find (&str, 0, "ill", NULL)) _dbus_assert_not_reached ("Did find 'ill'"); if (_dbus_string_find (&str, 0, "q", NULL)) _dbus_assert_not_reached ("Did find 'q'"); if (!_dbus_string_find_to (&str, 0, 2, "He", NULL)) _dbus_assert_not_reached ("Didn't find 'He'"); if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL)) _dbus_assert_not_reached ("Did find 'Hello'"); if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i)) _dbus_assert_not_reached ("Did not find 'H'"); _dbus_assert (i == 0); if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i)) _dbus_assert_not_reached ("Did not find 'o'"); _dbus_assert (i == _dbus_string_get_length (&str) - 1); if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i)) _dbus_assert_not_reached ("Did find 'o'"); _dbus_assert (i == -1); if (_dbus_string_find_byte_backward (&str, 1, 'e', &i)) _dbus_assert_not_reached ("Did find 'e'"); _dbus_assert (i == -1); if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i)) _dbus_assert_not_reached ("Didn't find 'e'"); _dbus_assert (i == 1); _dbus_string_free (&str); /* Hex encoding */ _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string"); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("could not init string"); if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0)) _dbus_assert_not_reached ("deccoded bogus hex string with no error"); _dbus_assert (end == 8); _dbus_string_free (&other); test_roundtrips (test_hex_roundtrip); _dbus_string_free (&str); { int found, found_len; _dbus_string_init_const (&str, "012\r\n567\n90"); if (!_dbus_string_find_eol (&str, 0, &found, &found_len) || found != 3 || found_len != 2) _dbus_assert_not_reached ("Did not find '\\r\\n'"); if (found != 3 || found_len != 2) _dbus_assert_not_reached ("invalid return values"); if (!_dbus_string_find_eol (&str, 5, &found, &found_len)) _dbus_assert_not_reached ("Did not find '\\n'"); if (found != 8 || found_len != 1) _dbus_assert_not_reached ("invalid return values"); if (_dbus_string_find_eol (&str, 9, &found, &found_len)) _dbus_assert_not_reached ("Found not expected '\\n'"); else if (found != 11 || found_len != 0) _dbus_assert_not_reached ("invalid return values '\\n'"); found = -1; found_len = -1; _dbus_string_init_const (&str, ""); if (_dbus_string_find_eol (&str, 0, &found, &found_len)) _dbus_assert_not_reached ("found an eol in an empty string"); _dbus_assert (found == 0); _dbus_assert (found_len == 0); found = -1; found_len = -1; _dbus_string_init_const (&str, "foobar"); if (_dbus_string_find_eol (&str, 0, &found, &found_len)) _dbus_assert_not_reached ("found eol in string that lacks one"); _dbus_assert (found == 6); _dbus_assert (found_len == 0); found = -1; found_len = -1; _dbus_string_init_const (&str, "foobar\n"); if (!_dbus_string_find_eol (&str, 0, &found, &found_len)) _dbus_assert_not_reached ("did not find eol in string that has one at end"); _dbus_assert (found == 6); _dbus_assert (found_len == 1); } { DBusString line; #define FIRST_LINE "this is a line" #define SECOND_LINE "this is a second line" /* third line is empty */ #define THIRD_LINE "" #define FOURTH_LINE "this is a fourth line" if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, FIRST_LINE "\n" SECOND_LINE "\r\n" THIRD_LINE "\n" FOURTH_LINE)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_init (&line)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_pop_line (&str, &line)) _dbus_assert_not_reached ("failed to pop first line"); _dbus_assert (_dbus_string_equal_c_str (&line, FIRST_LINE)); if (!_dbus_string_pop_line (&str, &line)) _dbus_assert_not_reached ("failed to pop second line"); _dbus_assert (_dbus_string_equal_c_str (&line, SECOND_LINE)); if (!_dbus_string_pop_line (&str, &line)) _dbus_assert_not_reached ("failed to pop third line"); _dbus_assert (_dbus_string_equal_c_str (&line, THIRD_LINE)); if (!_dbus_string_pop_line (&str, &line)) _dbus_assert_not_reached ("failed to pop fourth line"); _dbus_assert (_dbus_string_equal_c_str (&line, FOURTH_LINE)); _dbus_string_free (&str); _dbus_string_free (&line); } { if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); for (i = 0; i < 10000; i++) if (!_dbus_string_append (&str, "abcdefghijklmnopqrstuvwxyz")) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_set_length (&str, 10)) _dbus_assert_not_reached ("failed to set length"); /* actually compact */ if (!_dbus_string_compact (&str, 2048)) _dbus_assert_not_reached ("failed to compact after set_length"); /* peek inside to make sure it worked */ if (((DBusRealString *)&str)->allocated > 30) _dbus_assert_not_reached ("compacting string didn't do anything"); if (!_dbus_string_equal_c_str (&str, "abcdefghij")) _dbus_assert_not_reached ("unexpected content after compact"); /* compact nothing */ if (!_dbus_string_compact (&str, 2048)) _dbus_assert_not_reached ("failed to compact 2nd time"); if (!_dbus_string_equal_c_str (&str, "abcdefghij")) _dbus_assert_not_reached ("unexpected content after 2nd compact"); /* and make sure it still works...*/ if (!_dbus_string_append (&str, "123456")) _dbus_assert_not_reached ("failed to append after compact"); if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) _dbus_assert_not_reached ("unexpected content after append"); /* after growing automatically, this should do nothing */ if (!_dbus_string_compact (&str, 20000)) _dbus_assert_not_reached ("failed to compact after grow"); /* but this one will do something */ if (!_dbus_string_compact (&str, 0)) _dbus_assert_not_reached ("failed to compact after grow"); if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) _dbus_assert_not_reached ("unexpected content"); if (!_dbus_string_append (&str, "!@#$%")) _dbus_assert_not_reached ("failed to append after compact"); if (!_dbus_string_equal_c_str (&str, "abcdefghij123456!@#$%")) _dbus_assert_not_reached ("unexpected content"); _dbus_string_free (&str); } { const char two_strings[] = "one\ttwo"; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_init (&other)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, two_strings)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_split_on_byte (&str, '\t', &other)) _dbus_assert_not_reached ("no memory or delimiter not found"); if (strcmp (_dbus_string_get_data (&str), "one") != 0) _dbus_assert_not_reached ("left side after split on tab is wrong"); if (strcmp (_dbus_string_get_data (&other), "two") != 0) _dbus_assert_not_reached ("right side after split on tab is wrong"); _dbus_string_free (&str); _dbus_string_free (&other); } { const char upper_string[] = "TOUPPERSTRING"; const char lower_string[] = "toupperstring"; const char lower2_string[] = "toupperSTRING"; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, upper_string)) _dbus_assert_not_reached ("no memory"); _dbus_string_tolower_ascii (&str, 0, _dbus_string_get_length(&str)); if (!_dbus_string_equal_c_str (&str, lower_string)) _dbus_assert_not_reached ("_dbus_string_tolower_ascii failed"); _dbus_string_free (&str); if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, upper_string)) _dbus_assert_not_reached ("no memory"); _dbus_string_tolower_ascii (&str, 0, 7); if (!_dbus_string_equal_c_str (&str, lower2_string)) _dbus_assert_not_reached ("_dbus_string_tolower_ascii failed in partial conversion"); _dbus_string_free (&str); } { const char lower_string[] = "toupperstring"; const char upper_string[] = "TOUPPERSTRING"; const char upper2_string[] = "TOUPPERstring"; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, lower_string)) _dbus_assert_not_reached ("no memory"); _dbus_string_toupper_ascii (&str, 0, _dbus_string_get_length(&str)); if (!_dbus_string_equal_c_str (&str, upper_string)) _dbus_assert_not_reached ("_dbus_string_toupper_ascii failed"); _dbus_string_free (&str); if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append (&str, lower_string)) _dbus_assert_not_reached ("no memory"); _dbus_string_toupper_ascii (&str, 0, 7); if (!_dbus_string_equal_c_str (&str, upper2_string)) _dbus_assert_not_reached ("_dbus_string_toupper_ascii failed in partial conversion"); _dbus_string_free (&str); } return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-spawn.h0000644000175000017500000000673112602773110015735 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-spawn.h Wrapper around fork/exec * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SPAWN_H #define DBUS_SPAWN_H #include #include #include DBUS_BEGIN_DECLS typedef void (* DBusSpawnChildSetupFunc) (void *user_data); typedef struct DBusBabysitter DBusBabysitter; typedef void (* DBusBabysitterFinishedFunc) (DBusBabysitter *sitter, void *user_data); dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, const char *log_name, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error); void _dbus_babysitter_set_result_function (DBusBabysitter *sitter, DBusBabysitterFinishedFunc finished, void *user_data); DBusBabysitter* _dbus_babysitter_ref (DBusBabysitter *sitter); void _dbus_babysitter_unref (DBusBabysitter *sitter); void _dbus_babysitter_kill_child (DBusBabysitter *sitter); dbus_bool_t _dbus_babysitter_get_child_exited (DBusBabysitter *sitter); void _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, DBusError *error); dbus_bool_t _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, int *status); dbus_bool_t _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_END_DECLS #endif /* DBUS_SPAWN_H */ dbus-1.10.6/dbus/dbus-socket-set-poll.c0000644000175000017500000002123412602773110017620 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-socket-set-poll.c - a socket set implemented via _dbus_poll * * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * */ #include #include "dbus-socket-set.h" #include #include #include #include #ifndef DOXYGEN_SHOULD_SKIP_THIS typedef struct { DBusSocketSet parent; DBusPollFD *fds; int n_fds; int n_reserved; int n_allocated; } DBusSocketSetPoll; #define REALLOC_INCREMENT 8 #define MINIMUM_SIZE 8 /* If we're in the regression tests, force reallocation to happen sooner */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #define DEFAULT_SIZE_HINT 1 #else #define DEFAULT_SIZE_HINT MINIMUM_SIZE #endif static inline DBusSocketSetPoll * socket_set_poll_cast (DBusSocketSet *set) { _dbus_assert (set->cls == &_dbus_socket_set_poll_class); return (DBusSocketSetPoll *) set; } /* this is safe to call on a partially-allocated socket set */ static void socket_set_poll_free (DBusSocketSet *set) { DBusSocketSetPoll *self = socket_set_poll_cast (set); dbus_free (self->fds); dbus_free (self); _dbus_verbose ("freed socket set %p\n", self); } DBusSocketSet * _dbus_socket_set_poll_new (int size_hint) { DBusSocketSetPoll *ret; if (size_hint <= 0) size_hint = DEFAULT_SIZE_HINT; ret = dbus_new0 (DBusSocketSetPoll, 1); if (ret == NULL) return NULL; ret->parent.cls = &_dbus_socket_set_poll_class; ret->n_fds = 0; ret->n_allocated = size_hint; ret->fds = dbus_new0 (DBusPollFD, size_hint); if (ret->fds == NULL) { /* socket_set_poll_free specifically supports half-constructed * socket sets */ socket_set_poll_free ((DBusSocketSet *) ret); return NULL; } _dbus_verbose ("new socket set at %p\n", ret); return (DBusSocketSet *) ret; } static short watch_flags_to_poll_events (unsigned int flags) { short events = 0; if (flags & DBUS_WATCH_READABLE) events |= _DBUS_POLLIN; if (flags & DBUS_WATCH_WRITABLE) events |= _DBUS_POLLOUT; return events; } static dbus_bool_t socket_set_poll_add (DBusSocketSet *set, DBusPollable fd, unsigned int flags, dbus_bool_t enabled) { DBusSocketSetPoll *self = socket_set_poll_cast (set); #ifndef DBUS_DISABLE_ASSERT int i; for (i = 0; i < self->n_fds; i++) _dbus_assert (!_dbus_pollable_equals (self->fds[i].fd, fd)); #endif if (self->n_reserved >= self->n_allocated) { DBusPollFD *new_fds = dbus_realloc (self->fds, sizeof (DBusPollFD) * (self->n_allocated + REALLOC_INCREMENT)); _dbus_verbose ("inflating set %p from %d en/%d res/%d alloc to %d\n", self, self->n_fds, self->n_reserved, self->n_allocated, self->n_allocated + REALLOC_INCREMENT); if (new_fds == NULL) return FALSE; self->fds = new_fds; self->n_allocated += REALLOC_INCREMENT; } _dbus_verbose ("before adding fd %" DBUS_POLLABLE_FORMAT " to %p, %d en/%d res/%d alloc\n", _dbus_pollable_printable (fd), self, self->n_fds, self->n_reserved, self->n_allocated); _dbus_assert (self->n_reserved >= self->n_fds); _dbus_assert (self->n_allocated > self->n_reserved); self->n_reserved++; if (enabled) { self->fds[self->n_fds].fd = fd; self->fds[self->n_fds].events = watch_flags_to_poll_events (flags); self->n_fds++; } return TRUE; } static void socket_set_poll_enable (DBusSocketSet *set, DBusPollable fd, unsigned int flags) { DBusSocketSetPoll *self = socket_set_poll_cast (set); int i; for (i = 0; i < self->n_fds; i++) { if (_dbus_pollable_equals (self->fds[i].fd, fd)) { self->fds[i].events = watch_flags_to_poll_events (flags); return; } } /* we allocated space when the socket was added */ _dbus_assert (self->n_fds < self->n_reserved); _dbus_assert (self->n_reserved <= self->n_allocated); self->fds[self->n_fds].fd = fd; self->fds[self->n_fds].events = watch_flags_to_poll_events (flags); self->n_fds++; } static void socket_set_poll_disable (DBusSocketSet *set, DBusPollable fd) { DBusSocketSetPoll *self = socket_set_poll_cast (set); int i; for (i = 0; i < self->n_fds; i++) { if (_dbus_pollable_equals (self->fds[i].fd, fd)) { if (i != self->n_fds - 1) { self->fds[i].fd = self->fds[self->n_fds - 1].fd; self->fds[i].events = self->fds[self->n_fds - 1].events; } self->n_fds--; return; } } } static void socket_set_poll_remove (DBusSocketSet *set, DBusPollable fd) { DBusSocketSetPoll *self = socket_set_poll_cast (set); socket_set_poll_disable (set, fd); self->n_reserved--; _dbus_verbose ("after removing fd %" DBUS_POLLABLE_FORMAT " from %p, %d en/%d res/%d alloc\n", _dbus_pollable_printable (fd), self, self->n_fds, self->n_reserved, self->n_allocated); _dbus_assert (self->n_fds <= self->n_reserved); _dbus_assert (self->n_reserved <= self->n_allocated); if (self->n_reserved + MINIMUM_SIZE < self->n_allocated / 2) { /* Our array is twice as big as it needs to be - deflate it until it's * only slightly larger than the number reserved. */ DBusPollFD *new_fds = dbus_realloc (self->fds, sizeof (DBusPollFD) * (self->n_reserved + MINIMUM_SIZE)); _dbus_verbose ("before deflating %p, %d en/%d res/%d alloc\n", self, self->n_fds, self->n_reserved, self->n_allocated); if (_DBUS_UNLIKELY (new_fds == NULL)) { /* Weird. Oh well, never mind, the too-big array is untouched */ return; } self->fds = new_fds; self->n_allocated = self->n_reserved; } } static unsigned int watch_flags_from_poll_revents (short revents) { unsigned int condition = 0; if (revents & _DBUS_POLLIN) condition |= DBUS_WATCH_READABLE; if (revents & _DBUS_POLLOUT) condition |= DBUS_WATCH_WRITABLE; if (revents & _DBUS_POLLHUP) condition |= DBUS_WATCH_HANGUP; if (revents & _DBUS_POLLERR) condition |= DBUS_WATCH_ERROR; if (_DBUS_UNLIKELY (revents & _DBUS_POLLNVAL)) condition |= _DBUS_WATCH_NVAL; return condition; } /** This is basically Linux's epoll_wait(2) implemented in terms of poll(2); * it returns results into a caller-supplied buffer so we can be reentrant. */ static int socket_set_poll_poll (DBusSocketSet *set, DBusSocketEvent *revents, int max_events, int timeout_ms) { DBusSocketSetPoll *self = socket_set_poll_cast (set); int i; int n_events; int n_ready; _dbus_assert (max_events > 0); for (i = 0; i < self->n_fds; i++) self->fds[i].revents = 0; n_ready = _dbus_poll (self->fds, self->n_fds, timeout_ms); if (n_ready <= 0) return n_ready; n_events = 0; for (i = 0; i < self->n_fds; i++) { if (self->fds[i].revents != 0) { revents[n_events].fd = self->fds[i].fd; revents[n_events].flags = watch_flags_from_poll_revents (self->fds[i].revents); n_events += 1; /* We ignore events beyond max_events because we have nowhere to * put them. _dbus_poll is level-triggered, so we'll just be told * about them next time round the main loop anyway. */ if (n_events == max_events) return n_events; } } return n_events; } DBusSocketSetClass _dbus_socket_set_poll_class = { socket_set_poll_free, socket_set_poll_add, socket_set_poll_remove, socket_set_poll_enable, socket_set_poll_disable, socket_set_poll_poll }; #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ dbus-1.10.6/dbus/dbus-socket-set.c0000644000175000017500000000244112602773110016653 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * dbus-socket-set.c - used to bolt file descriptors onto a bus * * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * */ #include #include DBusSocketSet * _dbus_socket_set_new (int size_hint) { DBusSocketSet *ret; #ifdef DBUS_HAVE_LINUX_EPOLL ret = _dbus_socket_set_epoll_new (); if (ret != NULL) return ret; #endif ret = _dbus_socket_set_poll_new (size_hint); if (ret != NULL) return ret; return NULL; } dbus-1.10.6/dbus/dbus-socket-set.h0000644000175000017500000000746512602773110016673 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * dbus-socket-set.h - used to bolt file descriptors onto a bus * * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * */ #ifndef DBUS_SOCKET_SET_H #define DBUS_SOCKET_SET_H #ifndef DOXYGEN_SHOULD_SKIP_THIS #include #include typedef struct { DBusPollable fd; unsigned int flags; } DBusSocketEvent; typedef struct DBusSocketSet DBusSocketSet; typedef struct DBusSocketSetClass DBusSocketSetClass; struct DBusSocketSetClass { void (*free) (DBusSocketSet *self); dbus_bool_t (*add) (DBusSocketSet *self, DBusPollable fd, unsigned int flags, dbus_bool_t enabled); void (*remove) (DBusSocketSet *self, DBusPollable fd); void (*enable) (DBusSocketSet *self, DBusPollable fd, unsigned int flags); void (*disable) (DBusSocketSet *self, DBusPollable fd); int (*poll) (DBusSocketSet *self, DBusSocketEvent *revents, int max_events, int timeout_ms); }; struct DBusSocketSet { DBusSocketSetClass *cls; }; DBusSocketSet *_dbus_socket_set_new (int size_hint); static inline void _dbus_socket_set_free (DBusSocketSet *self) { (self->cls->free) (self); } static inline dbus_bool_t _dbus_socket_set_add (DBusSocketSet *self, DBusPollable fd, unsigned int flags, dbus_bool_t enabled) { return (self->cls->add) (self, fd, flags, enabled); } static inline void _dbus_socket_set_remove (DBusSocketSet *self, DBusPollable fd) { (self->cls->remove) (self, fd); } static inline void _dbus_socket_set_enable (DBusSocketSet *self, DBusPollable fd, unsigned int flags) { (self->cls->enable) (self, fd, flags); } static inline void _dbus_socket_set_disable (DBusSocketSet *self, DBusPollable fd) { (self->cls->disable) (self, fd); } static inline int _dbus_socket_set_poll (DBusSocketSet *self, DBusSocketEvent *revents, int max_events, int timeout_ms) { return (self->cls->poll) (self, revents, max_events, timeout_ms); } /* concrete implementations, not necessarily built on all platforms */ extern DBusSocketSetClass _dbus_socket_set_poll_class; extern DBusSocketSetClass _dbus_socket_set_epoll_class; DBusSocketSet *_dbus_socket_set_poll_new (int size_hint); DBusSocketSet *_dbus_socket_set_epoll_new (void); #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* multiple-inclusion guard */ dbus-1.10.6/dbus/dbus-spawn-win.c0000644000175000017500000006261512622707003016526 0ustar00smcvsmcv00000000000000#include //#define SPAWN_DEBUG #if !defined(SPAWN_DEBUG) || defined(_MSC_VER) #define PING() #else #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr) #endif #include /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-spawn-win32.c Wrapper around g_spawn * * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2005 Novell, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "dbus-spawn.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-win.h" #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-protocol.h" #define WIN32_LEAN_AND_MEAN #include //#define STRICT //#include //#undef STRICT #include #undef interface #include #ifndef DBUS_WINCE #include #endif /** * Babysitter implementation details */ struct DBusBabysitter { int refcount; HANDLE start_sync_event; #ifdef DBUS_ENABLE_EMBEDDED_TESTS HANDLE end_sync_event; #endif char *log_name; DBusSpawnChildSetupFunc child_setup; void *user_data; int argc; char **argv; char **envp; HANDLE child_handle; DBusSocket socket_to_babysitter; /* Connection to the babysitter thread */ DBusSocket socket_to_main; DBusWatchList *watches; DBusWatch *sitter_watch; DBusBabysitterFinishedFunc finished_cb; void *finished_data; dbus_bool_t have_spawn_errno; int spawn_errno; dbus_bool_t have_child_status; int child_status; }; static DBusBabysitter* _dbus_babysitter_new (void) { DBusBabysitter *sitter; sitter = dbus_new0 (DBusBabysitter, 1); if (sitter == NULL) return NULL; sitter->refcount = 1; sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); if (sitter->start_sync_event == NULL) { _dbus_babysitter_unref (sitter); return NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); if (sitter->end_sync_event == NULL) { _dbus_babysitter_unref (sitter); return NULL; } #endif sitter->child_handle = NULL; sitter->socket_to_babysitter = sitter->socket_to_main = _dbus_socket_get_invalid (); sitter->argc = 0; sitter->argv = NULL; sitter->envp = NULL; sitter->watches = _dbus_watch_list_new (); if (sitter->watches == NULL) { _dbus_babysitter_unref (sitter); return NULL; } sitter->have_spawn_errno = FALSE; sitter->have_child_status = FALSE; return sitter; } /** * Increment the reference count on the babysitter object. * * @param sitter the babysitter * @returns the babysitter */ DBusBabysitter * _dbus_babysitter_ref (DBusBabysitter *sitter) { PING(); _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount += 1; return sitter; } static void close_socket_to_babysitter (DBusBabysitter *sitter) { _dbus_verbose ("Closing babysitter\n"); if (sitter->sitter_watch != NULL) { _dbus_assert (sitter->watches != NULL); _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch); _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->socket_to_babysitter.sock != INVALID_SOCKET) { _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter.sock = INVALID_SOCKET; } } /** * Decrement the reference count on the babysitter object. * * @param sitter the babysitter */ void _dbus_babysitter_unref (DBusBabysitter *sitter) { int i; PING(); _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount -= 1; if (sitter->refcount == 0) { close_socket_to_babysitter (sitter); if (sitter->socket_to_main.sock != INVALID_SOCKET) { _dbus_close_socket (sitter->socket_to_main, NULL); sitter->socket_to_main.sock = INVALID_SOCKET; } PING(); if (sitter->argv != NULL) { for (i = 0; i < sitter->argc; i++) if (sitter->argv[i] != NULL) { dbus_free (sitter->argv[i]); sitter->argv[i] = NULL; } dbus_free (sitter->argv); sitter->argv = NULL; } if (sitter->envp != NULL) { char **e = sitter->envp; while (*e) dbus_free (*e++); dbus_free (sitter->envp); sitter->envp = NULL; } if (sitter->child_handle != NULL) { CloseHandle (sitter->child_handle); sitter->child_handle = NULL; } if (sitter->sitter_watch) { _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->watches) _dbus_watch_list_free (sitter->watches); if (sitter->start_sync_event != NULL) { PING(); CloseHandle (sitter->start_sync_event); sitter->start_sync_event = NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (sitter->end_sync_event != NULL) { CloseHandle (sitter->end_sync_event); sitter->end_sync_event = NULL; } #endif dbus_free (sitter->log_name); dbus_free (sitter); } } void _dbus_babysitter_kill_child (DBusBabysitter *sitter) { PING(); if (sitter->child_handle == NULL) return; /* child is already dead, or we're so hosed we'll never recover */ PING(); TerminateProcess (sitter->child_handle, 12345); } /** * Checks whether the child has exited, without blocking. * * @param sitter the babysitter */ dbus_bool_t _dbus_babysitter_get_child_exited (DBusBabysitter *sitter) { PING(); return (sitter->child_handle == NULL); } /** * Gets the exit status of the child. We do this so implementation specific * detail is not cluttering up dbus, for example the system launcher code. * This can only be called if the child has exited, i.e. call * _dbus_babysitter_get_child_exited(). It returns FALSE if the child * did not return a status code, e.g. because the child was signaled * or we failed to ever launch the child in the first place. * * @param sitter the babysitter * @param status the returned status code * @returns #FALSE on failure */ dbus_bool_t _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, int *status) { if (!_dbus_babysitter_get_child_exited (sitter)) _dbus_assert_not_reached ("Child has not exited"); if (!sitter->have_child_status || sitter->child_status == STILL_ACTIVE) return FALSE; *status = sitter->child_status; return TRUE; } /** * Sets the #DBusError with an explanation of why the spawned * child process exited (on a signal, or whatever). If * the child process has not exited, does nothing (error * will remain unset). * * @param sitter the babysitter * @param error an error to fill in */ void _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, DBusError *error) { PING(); if (!_dbus_babysitter_get_child_exited (sitter)) return; PING(); if (sitter->have_spawn_errno) { char *emsg = _dbus_win_error_string (sitter->spawn_errno); dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "Failed to execute program %s: %s", sitter->log_name, emsg); _dbus_win_free_error_string (emsg); } else if (sitter->have_child_status) { PING(); dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, "Process %s exited with status %d", sitter->log_name, sitter->child_status); } else { PING(); dbus_set_error (error, DBUS_ERROR_FAILED, "Process %s exited, status unknown", sitter->log_name); } PING(); } dbus_bool_t _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { PING(); return _dbus_watch_list_set_functions (sitter->watches, add_function, remove_function, toggled_function, data, free_data_function); } static dbus_bool_t handle_watch (DBusWatch *watch, unsigned int condition, void *data) { DBusBabysitter *sitter = data; /* On Unix dbus-spawn uses a babysitter *process*, thus it has to * actually send the exit statuses, error codes and whatnot through * sockets and/or pipes. On Win32, the babysitter is jus a thread, * so it can set the status fields directly in the babysitter struct * just fine. The socket pipe is used just so we can watch it with * select(), as soon as anything is written to it we know that the * babysitter thread has recorded the status in the babysitter * struct. */ PING(); close_socket_to_babysitter (sitter); PING(); if (_dbus_babysitter_get_child_exited (sitter) && sitter->finished_cb != NULL) { sitter->finished_cb (sitter, sitter->finished_data); sitter->finished_cb = NULL; } return TRUE; } /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ static int protect_argv (char **argv, char ***new_argv) { int i; int argc = 0; while (argv[argc]) ++argc; *new_argv = dbus_malloc ((argc + 1) * sizeof (char *)); if (*new_argv == NULL) return -1; for (i = 0; i < argc; i++) (*new_argv)[i] = NULL; /* Quote each argv element if necessary, so that it will get * reconstructed correctly in the C runtime startup code. Note that * the unquoting algorithm in the C runtime is really weird, and * rather different than what Unix shells do. See stdargv.c in the C * runtime sources (in the Platform SDK, in src/crt). * * Note that an new_argv[0] constructed by this function should * *not* be passed as the filename argument to a spawn* or exec* * family function. That argument should be the real file name * without any quoting. */ for (i = 0; i < argc; i++) { char *p = argv[i]; char *q; int len = 0; int need_dblquotes = FALSE; while (*p) { if (*p == ' ' || *p == '\t') need_dblquotes = TRUE; else if (*p == '"') len++; else if (*p == '\\') { char *pp = p; while (*pp && *pp == '\\') pp++; if (*pp == '"') len++; } len++; p++; } q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1); if (q == NULL) return -1; p = argv[i]; if (need_dblquotes) *q++ = '"'; while (*p) { if (*p == '"') *q++ = '\\'; else if (*p == '\\') { char *pp = p; while (*pp && *pp == '\\') pp++; if (*pp == '"') *q++ = '\\'; } *q++ = *p; p++; } if (need_dblquotes) *q++ = '"'; *q++ = '\0'; /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ } (*new_argv)[argc] = NULL; return argc; } /* From GPGME, relicensed by g10 Code GmbH. */ static char * compose_string (char **strings, char separator) { int i; int n = 0; char *buf; char *p; if (!strings || !strings[0]) return 0; for (i = 0; strings[i]; i++) n += strlen (strings[i]) + 1; n++; buf = p = malloc (n); if (!buf) return NULL; for (i = 0; strings[i]; i++) { strcpy (p, strings[i]); p += strlen (strings[i]); *(p++) = separator; } p--; *(p++) = '\0'; *p = '\0'; return buf; } static char * build_commandline (char **argv) { return compose_string (argv, ' '); } static char * build_env_string (char** envp) { return compose_string (envp, '\0'); } static HANDLE spawn_program (char* name, char** argv, char** envp) { PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; STARTUPINFOA si; char *arg_string, *env_string; BOOL result; #ifdef DBUS_WINCE if (argv && argv[0]) arg_string = build_commandline (argv + 1); else arg_string = NULL; #else arg_string = build_commandline (argv); #endif if (!arg_string) return INVALID_HANDLE_VALUE; env_string = build_env_string(envp); memset (&si, 0, sizeof (si)); si.cb = sizeof (si); #ifdef DBUS_WINCE result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0, #else result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0, #endif (LPVOID)env_string, NULL, &si, &pi); free (arg_string); if (env_string) free (env_string); if (!result) return INVALID_HANDLE_VALUE; CloseHandle (pi.hThread); return pi.hProcess; } static DWORD __stdcall babysitter (void *parameter) { int ret = 0; DBusBabysitter *sitter = (DBusBabysitter *) parameter; PING(); _dbus_babysitter_ref (sitter); if (sitter->child_setup) { PING(); (*sitter->child_setup) (sitter->user_data); } _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name); PING(); sitter->child_handle = spawn_program (sitter->log_name, sitter->argv, sitter->envp); PING(); if (sitter->child_handle == (HANDLE) -1) { sitter->child_handle = NULL; sitter->have_spawn_errno = TRUE; sitter->spawn_errno = GetLastError(); } PING(); SetEvent (sitter->start_sync_event); if (sitter->child_handle != NULL) { DWORD status; PING(); // wait until process finished WaitForSingleObject (sitter->child_handle, INFINITE); PING(); ret = GetExitCodeProcess (sitter->child_handle, &status); if (ret) { sitter->child_status = status; sitter->have_child_status = TRUE; } CloseHandle (sitter->child_handle); sitter->child_handle = NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS SetEvent (sitter->end_sync_event); #endif PING(); send (sitter->socket_to_main.sock, " ", 1, 0); _dbus_babysitter_unref (sitter); return ret ? 0 : 1; } dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, const char *log_name, char **argv, char **envp, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; HANDLE sitter_thread; DWORD sitter_thread_id; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (argv[0] != NULL); *sitter_p = NULL; PING(); sitter = _dbus_babysitter_new (); if (sitter == NULL) { _DBUS_SET_OOM (error); return FALSE; } sitter->child_setup = child_setup; sitter->user_data = user_data; sitter->log_name = _dbus_strdup (log_name); if (sitter->log_name == NULL && log_name != NULL) { _DBUS_SET_OOM (error); goto out0; } if (sitter->log_name == NULL) sitter->log_name = _dbus_strdup (argv[0]); if (sitter->log_name == NULL) { _DBUS_SET_OOM (error); goto out0; } PING(); if (!_dbus_socketpair (&sitter->socket_to_babysitter, &sitter->socket_to_main, FALSE, error)) goto out0; sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); PING(); if (sitter->sitter_watch == NULL) { _DBUS_SET_OOM (error); goto out0; } PING(); if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; _DBUS_SET_OOM (error); goto out0; } sitter->argc = protect_argv (argv, &sitter->argv); if (sitter->argc == -1) { _DBUS_SET_OOM (error); goto out0; } sitter->envp = envp; PING(); sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter, sitter, 0, &sitter_thread_id); if (sitter_thread == 0) { PING(); dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to create new thread"); goto out0; } CloseHandle (sitter_thread); PING(); WaitForSingleObject (sitter->start_sync_event, INFINITE); PING(); if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); _DBUS_ASSERT_ERROR_IS_CLEAR (error); PING(); return TRUE; out0: _dbus_babysitter_unref (sitter); return FALSE; } void _dbus_babysitter_set_result_function (DBusBabysitter *sitter, DBusBabysitterFinishedFunc finished, void *user_data) { sitter->finished_cb = finished; sitter->finished_data = user_data; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS static char * get_test_exec (const char *exe, DBusString *scratch_space) { const char *dbus_test_exec; dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC"); if (dbus_test_exec == NULL) dbus_test_exec = DBUS_TEST_EXEC; if (!_dbus_string_init (scratch_space)) return NULL; if (!_dbus_string_append_printf (scratch_space, "%s/%s%s", dbus_test_exec, exe, DBUS_EXEEXT)) { _dbus_string_free (scratch_space); return NULL; } return _dbus_string_get_data (scratch_space); } #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) static void _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) { if (sitter->child_handle == NULL) return; WaitForSingleObject (sitter->end_sync_event, INFINITE); } static dbus_bool_t check_spawn_nonexistent (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter; DBusError error; sitter = NULL; dbus_error_init (&error); /*** Test launching nonexistent binary */ argv[0] = "/this/does/not/exist/32542sdgafgafdg"; if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching nonexistent executable\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) { _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_segfault (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter; DBusError error; DBusString argv0; sitter = NULL; dbus_error_init (&error); /*** Test launching segfault binary */ argv[0] = get_test_exec ("test-segfault", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching segfaulting binary\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) { _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_exit (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter; DBusError error; DBusString argv0; sitter = NULL; dbus_error_init (&error); /*** Test launching exit failure binary */ argv[0] = get_test_exec ("test-exit", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) { _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_and_kill (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter; DBusError error; DBusString argv0; sitter = NULL; dbus_error_init (&error); /*** Test launching sleeping binary then killing it */ argv[0] = get_test_exec ("test-sleep-forever", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_kill_child (sitter); _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error after killing spawned binary\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) { _dbus_warn ("Not expecting error when killing executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } dbus_bool_t _dbus_spawn_test (const char *test_data_dir) { if (!_dbus_test_oom_handling ("spawn_nonexistent", check_spawn_nonexistent, NULL)) return FALSE; /* Don't run the obnoxious segfault test by default, * it's a pain to have to click all those error boxes. */ if (getenv ("DO_SEGFAULT_TEST")) if (!_dbus_test_oom_handling ("spawn_segfault", check_spawn_segfault, NULL)) return FALSE; if (!_dbus_test_oom_handling ("spawn_exit", check_spawn_exit, NULL)) return FALSE; if (!_dbus_test_oom_handling ("spawn_and_kill", check_spawn_and_kill, NULL)) return FALSE; return TRUE; } #endif dbus-1.10.6/dbus/dbus-sysdeps-util-win.c0000644000175000017500000016234212624705346020053 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #define STRSAFE_NO_DEPRECATE #include "dbus-sysdeps.h" #include "dbus-internals.h" #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-win.h" #include "dbus-sockets-win.h" #include "dbus-memory.h" #include "dbus-pipe.h" #include #include #if HAVE_ERRNO_H #include #endif #include // WSA error codes #ifndef DBUS_WINCE #include #include #include #endif /** * Does the chdir, fork, setsid, etc. to become a daemon process. * * @param pidfile #NULL, or pidfile to create * @param print_pid_pipe file descriptor to print daemon's pid to, or -1 for none * @param error return location for errors * @param keep_umask #TRUE to keep the original umask * @returns #FALSE on failure */ dbus_bool_t _dbus_become_daemon (const DBusString *pidfile, DBusPipe *print_pid_pipe, DBusError *error, dbus_bool_t keep_umask) { dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Cannot daemonize on Windows"); return FALSE; } /** * Creates a file containing the process ID. * * @param filename the filename to write to * @param pid our process ID * @param error return location for errors * @returns #FALSE on failure */ static dbus_bool_t _dbus_write_pid_file (const DBusString *filename, unsigned long pid, DBusError *error) { const char *cfilename; HANDLE hnd; char pidstr[20]; int total; int bytes_to_write; _DBUS_ASSERT_ERROR_IS_CLEAR (error); cfilename = _dbus_string_get_const_data (filename); hnd = CreateFileA (cfilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hnd == INVALID_HANDLE_VALUE) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not create PID file %s: %s", cfilename, emsg); _dbus_win_free_error_string (emsg); return FALSE; } if (snprintf (pidstr, sizeof (pidstr), "%lu\n", pid) < 0) { dbus_set_error (error, _dbus_error_from_system_errno (), "Failed to format PID for \"%s\": %s", cfilename, _dbus_strerror_from_errno ()); CloseHandle (hnd); return FALSE; } total = 0; bytes_to_write = strlen (pidstr);; while (total < bytes_to_write) { DWORD bytes_written; BOOL res; res = WriteFile (hnd, pidstr + total, bytes_to_write - total, &bytes_written, NULL); if (res == 0 || bytes_written <= 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not write to %s: %s", cfilename, emsg); _dbus_win_free_error_string (emsg); CloseHandle (hnd); return FALSE; } total += bytes_written; } if (CloseHandle (hnd) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not close file %s: %s", cfilename, emsg); _dbus_win_free_error_string (emsg); return FALSE; } return TRUE; } /** * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both * NULL. * * @param pidfile the file to write to or #NULL * @param print_pid_pipe the pipe to write to or #NULL * @param pid_to_write the pid to write out * @param error error on failure * @returns FALSE if error is set */ dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, DBusPipe *print_pid_pipe, dbus_pid_t pid_to_write, DBusError *error) { if (pidfile) { _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile)); if (!_dbus_write_pid_file (pidfile, pid_to_write, error)) { _dbus_verbose ("pid file write failed\n"); _DBUS_ASSERT_ERROR_IS_SET(error); return FALSE; } } else { _dbus_verbose ("No pid file requested\n"); } if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe)) { DBusString pid; int bytes; _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd); if (!_dbus_string_init (&pid)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append_int (&pid, pid_to_write) || !_dbus_string_append (&pid, "\n")) { _dbus_string_free (&pid); _DBUS_SET_OOM (error); return FALSE; } bytes = _dbus_string_get_length (&pid); if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes) { /* _dbus_pipe_write sets error only on failure, not short write */ if (error != NULL && !dbus_error_is_set(error)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Printing message bus PID: did not write enough bytes\n"); } _dbus_string_free (&pid); return FALSE; } _dbus_string_free (&pid); } else { _dbus_verbose ("No pid pipe to write to\n"); } return TRUE; } /** * Verify that after the fork we can successfully change to this user. * * @param user the username given in the daemon configuration * @returns #TRUE if username is valid */ dbus_bool_t _dbus_verify_daemon_user (const char *user) { return TRUE; } /** * Changes the user and group the bus is running as. * * @param user the user to become * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error) { return TRUE; } static void fd_limit_not_supported (DBusError *error) { dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "cannot change fd limit on this platform"); } DBusRLimit * _dbus_rlimit_save_fd_limit (DBusError *error) { fd_limit_not_supported (error); return NULL; } dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, DBusError *error) { fd_limit_not_supported (error); return FALSE; } dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, DBusError *error) { fd_limit_not_supported (error); return FALSE; } void _dbus_rlimit_free (DBusRLimit *lim) { /* _dbus_rlimit_save_fd_limit() cannot return non-NULL on Windows * so there cannot be anything to free */ _dbus_assert (lim == NULL); } void _dbus_init_system_log (dbus_bool_t is_daemon) { /* OutputDebugStringA doesn't need any special initialization, do nothing */ } /** * Log a message to the system log file (e.g. syslog on Unix). * * @param severity a severity value * @param msg a printf-style format string */ void _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) { va_list args; va_start (args, msg); _dbus_system_logv (severity, msg, args); va_end (args); } /** * Log a message to the system log file (e.g. syslog on Unix). * * @param severity a severity value * @param msg a printf-style format string * @param args arguments for the format string * * If the FATAL severity is given, this function will terminate the program * with an error code. */ void _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args) { char *s = ""; char buf[1024]; char format[1024]; switch(severity) { case DBUS_SYSTEM_LOG_INFO: s = "info"; break; case DBUS_SYSTEM_LOG_WARNING: s = "warning"; break; case DBUS_SYSTEM_LOG_SECURITY: s = "security"; break; case DBUS_SYSTEM_LOG_FATAL: s = "fatal"; break; } snprintf(format, sizeof(format), "%s%s", s ,msg); vsnprintf(buf, sizeof(buf), format, args); OutputDebugStringA(buf); if (severity == DBUS_SYSTEM_LOG_FATAL) exit (1); } /** Installs a signal handler * * @param sig the signal to handle * @param handler the handler */ void _dbus_set_signal_handler (int sig, DBusSignalHandler handler) { _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n"); } /** * stat() wrapper. * * @param filename the filename to stat * @param statbuf the stat info to fill in * @param error return location for error * @returns #FALSE if error was set */ dbus_bool_t _dbus_stat(const DBusString *filename, DBusStat *statbuf, DBusError *error) { const char *filename_c; WIN32_FILE_ATTRIBUTE_DATA wfad; char *lastdot; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (!GetFileAttributesExA (filename_c, GetFileExInfoStandard, &wfad)) { _dbus_win_set_error_from_win_error (error, GetLastError ()); return FALSE; } if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) statbuf->mode = _S_IFDIR; else statbuf->mode = _S_IFREG; statbuf->mode |= _S_IREAD; if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY) statbuf->mode |= _S_IWRITE; lastdot = strrchr (filename_c, '.'); if (lastdot && stricmp (lastdot, ".exe") == 0) statbuf->mode |= _S_IEXEC; statbuf->mode |= (statbuf->mode & 0700) >> 3; statbuf->mode |= (statbuf->mode & 0700) >> 6; statbuf->nlink = 1; #ifdef ENABLE_UID_TO_SID { PSID owner_sid, group_sid; PSECURITY_DESCRIPTOR sd; sd = NULL; rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, &owner_sid, &group_sid, NULL, NULL, &sd); if (rc != ERROR_SUCCESS) { _dbus_win_set_error_from_win_error (error, rc); if (sd != NULL) LocalFree (sd); return FALSE; } /* FIXME */ statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid); statbuf->gid = _dbus_win_sid_to_uid_t (group_sid); LocalFree (sd); } #else statbuf->uid = DBUS_UID_UNSET; statbuf->gid = DBUS_GID_UNSET; #endif statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow; statbuf->atime = (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) + wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); statbuf->mtime = (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) + wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); statbuf->ctime = (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) + wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); return TRUE; } /** * Internals of directory iterator */ struct DBusDirIter { HANDLE handle; WIN32_FIND_DATAA fileinfo; /* from FindFirst/FindNext */ dbus_bool_t finished; /* true if there are no more entries */ int offset; }; /** * Open a directory to iterate over. * * @param filename the directory name * @param error exception return object or #NULL * @returns new iterator, or #NULL on error */ DBusDirIter* _dbus_directory_open (const DBusString *filename, DBusError *error) { DBusDirIter *iter; DBusString filespec; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init_from_string (&filespec, filename)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Could not allocate memory for directory filename copy"); return NULL; } if (_dbus_string_ends_with_c_str (&filespec, "/") || _dbus_string_ends_with_c_str (&filespec, "\\") ) { if (!_dbus_string_append (&filespec, "*")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Could not append filename wildcard"); return NULL; } } else if (!_dbus_string_ends_with_c_str (&filespec, "*")) { if (!_dbus_string_append (&filespec, "\\*")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Could not append filename wildcard 2"); return NULL; } } iter = dbus_new0 (DBusDirIter, 1); if (iter == NULL) { _dbus_string_free (&filespec); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Could not allocate memory for directory iterator"); return NULL; } iter->finished = FALSE; iter->offset = 0; iter->handle = FindFirstFileA (_dbus_string_get_const_data (&filespec), &(iter->fileinfo)); if (iter->handle == INVALID_HANDLE_VALUE) { if (GetLastError () == ERROR_NO_MORE_FILES) iter->finished = TRUE; else { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to read directory \"%s\": %s", _dbus_string_get_const_data (filename), emsg); _dbus_win_free_error_string (emsg); dbus_free ( iter ); _dbus_string_free (&filespec); return NULL; } } _dbus_string_free (&filespec); return iter; } /** * Get next file in the directory. Will not return "." or ".." on * UNIX. If an error occurs, the contents of "filename" are * undefined. The error is never set if the function succeeds. * * @param iter the iterator * @param filename string to be set to the next file in the dir * @param error return location for error * @returns #TRUE if filename was filled in with a new filename */ dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, DBusError *error) { int saved_err = GetLastError(); _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: SetLastError (0); if (!iter || iter->finished) return FALSE; if (iter->offset > 0) { if (FindNextFileA (iter->handle, &(iter->fileinfo)) == 0) { if (GetLastError() == ERROR_NO_MORE_FILES) { SetLastError(saved_err); iter->finished = 1; } else { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to get next in directory: %s", emsg); _dbus_win_free_error_string (emsg); return FALSE; } } } iter->offset++; if (iter->finished) return FALSE; if (iter->fileinfo.cFileName[0] == '.' && (iter->fileinfo.cFileName[1] == '\0' || (iter->fileinfo.cFileName[1] == '.' && iter->fileinfo.cFileName[2] == '\0'))) goto again; _dbus_string_set_length (filename, 0); if (!_dbus_string_append (filename, iter->fileinfo.cFileName)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "No memory to read directory entry"); return FALSE; } return TRUE; } /** * Closes a directory iteration. */ void _dbus_directory_close (DBusDirIter *iter) { if (!iter) return; FindClose(iter->handle); dbus_free (iter); } /** @} */ /* End of DBusInternalsUtils functions */ /** * @addtogroup DBusString * * @{ */ /** * Get the directory name from a complete filename * @param filename the filename * @param dirname string to append directory name to * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_get_dirname(const DBusString *filename, DBusString *dirname) { int sep; _dbus_assert (filename != dirname); _dbus_assert (filename != NULL); _dbus_assert (dirname != NULL); /* Ignore any separators on the end */ sep = _dbus_string_get_length (filename); if (sep == 0) return _dbus_string_append (dirname, "."); /* empty string passed in */ while (sep > 0 && (_dbus_string_get_byte (filename, sep - 1) == '/' || _dbus_string_get_byte (filename, sep - 1) == '\\')) --sep; _dbus_assert (sep >= 0); if (sep == 0 || (sep == 2 && _dbus_string_get_byte (filename, 1) == ':' && isalpha (_dbus_string_get_byte (filename, 0)))) return _dbus_string_copy_len (filename, 0, sep + 1, dirname, _dbus_string_get_length (dirname)); { int sep1, sep2; _dbus_string_find_byte_backward (filename, sep, '/', &sep1); _dbus_string_find_byte_backward (filename, sep, '\\', &sep2); sep = MAX (sep1, sep2); } if (sep < 0) return _dbus_string_append (dirname, "."); while (sep > 0 && (_dbus_string_get_byte (filename, sep - 1) == '/' || _dbus_string_get_byte (filename, sep - 1) == '\\')) --sep; _dbus_assert (sep >= 0); if ((sep == 0 || (sep == 2 && _dbus_string_get_byte (filename, 1) == ':' && isalpha (_dbus_string_get_byte (filename, 0)))) && (_dbus_string_get_byte (filename, sep) == '/' || _dbus_string_get_byte (filename, sep) == '\\')) return _dbus_string_copy_len (filename, 0, sep + 1, dirname, _dbus_string_get_length (dirname)); else return _dbus_string_copy_len (filename, 0, sep - 0, dirname, _dbus_string_get_length (dirname)); } /** * Checks to see if the UNIX user ID matches the UID of * the process. Should always return #FALSE on Windows. * * @param uid the UNIX user ID * @returns #TRUE if this uid owns the process. */ dbus_bool_t _dbus_unix_user_is_process_owner (dbus_uid_t uid) { return FALSE; } dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid) { return TRUE; } /*===================================================================== unix emulation functions - should be removed sometime in the future =====================================================================*/ /** * Checks to see if the UNIX user ID is at the console. * Should always fail on Windows (set the error to * #DBUS_ERROR_NOT_SUPPORTED). * * @param uid UID of person to check * @param error return location for errors * @returns #TRUE if the UID is the same as the console user and there are no errors */ dbus_bool_t _dbus_unix_user_is_at_console (dbus_uid_t uid, DBusError *error) { dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "UNIX user IDs not supported on Windows\n"); return FALSE; } /** * Parse a UNIX group from the bus config file. On Windows, this should * simply always fail (just return #FALSE). * * @param groupname the groupname text * @param gid_p place to return the gid * @returns #TRUE on success */ dbus_bool_t _dbus_parse_unix_group_from_config (const DBusString *groupname, dbus_gid_t *gid_p) { return FALSE; } /** * Parse a UNIX user from the bus config file. On Windows, this should * simply always fail (just return #FALSE). * * @param username the username text * @param uid_p place to return the uid * @returns #TRUE on success */ dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username, dbus_uid_t *uid_p) { return FALSE; } /** * Gets all groups corresponding to the given UNIX user ID. On UNIX, * just calls _dbus_groups_from_uid(). On Windows, should always * fail since we don't know any UNIX groups. * * @param uid the UID * @param group_ids return location for array of group IDs * @param n_group_ids return location for length of returned array * @returns #TRUE if the UID existed and we got some credentials */ dbus_bool_t _dbus_unix_groups_from_uid (dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids) { return FALSE; } /** @} */ /* DBusString stuff */ /************************************************************************ error handling ************************************************************************/ /* lan manager error codes */ const char* _dbus_lm_strerror(int error_number) { #ifdef DBUS_WINCE // TODO return "unknown"; #else const char *msg; switch (error_number) { case NERR_NetNotStarted: return "The workstation driver is not installed."; case NERR_UnknownServer: return "The server could not be located."; case NERR_ShareMem: return "An internal error occurred. The network cannot access a shared memory segment."; case NERR_NoNetworkResource: return "A network resource shortage occurred."; case NERR_RemoteOnly: return "This operation is not supported on workstations."; case NERR_DevNotRedirected: return "The device is not connected."; case NERR_ServerNotStarted: return "The Server service is not started."; case NERR_ItemNotFound: return "The queue is empty."; case NERR_UnknownDevDir: return "The device or directory does not exist."; case NERR_RedirectedPath: return "The operation is invalid on a redirected resource."; case NERR_DuplicateShare: return "The name has already been shared."; case NERR_NoRoom: return "The server is currently out of the requested resource."; case NERR_TooManyItems: return "Requested addition of items exceeds the maximum allowed."; case NERR_InvalidMaxUsers: return "The Peer service supports only two simultaneous users."; case NERR_BufTooSmall: return "The API return buffer is too small."; case NERR_RemoteErr: return "A remote API error occurred."; case NERR_LanmanIniError: return "An error occurred when opening or reading the configuration file."; case NERR_NetworkError: return "A general network error occurred."; case NERR_WkstaInconsistentState: return "The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service."; case NERR_WkstaNotStarted: return "The Workstation service has not been started."; case NERR_BrowserNotStarted: return "The requested information is not available."; case NERR_InternalError: return "An internal error occurred."; case NERR_BadTransactConfig: return "The server is not configured for transactions."; case NERR_InvalidAPI: return "The requested API is not supported on the remote server."; case NERR_BadEventName: return "The event name is invalid."; case NERR_DupNameReboot: return "The computer name already exists on the network. Change it and restart the computer."; case NERR_CfgCompNotFound: return "The specified component could not be found in the configuration information."; case NERR_CfgParamNotFound: return "The specified parameter could not be found in the configuration information."; case NERR_LineTooLong: return "A line in the configuration file is too long."; case NERR_QNotFound: return "The printer does not exist."; case NERR_JobNotFound: return "The print job does not exist."; case NERR_DestNotFound: return "The printer destination cannot be found."; case NERR_DestExists: return "The printer destination already exists."; case NERR_QExists: return "The printer queue already exists."; case NERR_QNoRoom: return "No more printers can be added."; case NERR_JobNoRoom: return "No more print jobs can be added."; case NERR_DestNoRoom: return "No more printer destinations can be added."; case NERR_DestIdle: return "This printer destination is idle and cannot accept control operations."; case NERR_DestInvalidOp: return "This printer destination request contains an invalid control function."; case NERR_ProcNoRespond: return "The print processor is not responding."; case NERR_SpoolerNotLoaded: return "The spooler is not running."; case NERR_DestInvalidState: return "This operation cannot be performed on the print destination in its current state."; case NERR_QInvalidState: return "This operation cannot be performed on the printer queue in its current state."; case NERR_JobInvalidState: return "This operation cannot be performed on the print job in its current state."; case NERR_SpoolNoMemory: return "A spooler memory allocation failure occurred."; case NERR_DriverNotFound: return "The device driver does not exist."; case NERR_DataTypeInvalid: return "The data type is not supported by the print processor."; case NERR_ProcNotFound: return "The print processor is not installed."; case NERR_ServiceTableLocked: return "The service database is locked."; case NERR_ServiceTableFull: return "The service table is full."; case NERR_ServiceInstalled: return "The requested service has already been started."; case NERR_ServiceEntryLocked: return "The service does not respond to control actions."; case NERR_ServiceNotInstalled: return "The service has not been started."; case NERR_BadServiceName: return "The service name is invalid."; case NERR_ServiceCtlTimeout: return "The service is not responding to the control function."; case NERR_ServiceCtlBusy: return "The service control is busy."; case NERR_BadServiceProgName: return "The configuration file contains an invalid service program name."; case NERR_ServiceNotCtrl: return "The service could not be controlled in its present state."; case NERR_ServiceKillProc: return "The service ended abnormally."; case NERR_ServiceCtlNotValid: return "The requested pause or stop is not valid for this service."; case NERR_NotInDispatchTbl: return "The service control dispatcher could not find the service name in the dispatch table."; case NERR_BadControlRecv: return "The service control dispatcher pipe read failed."; case NERR_ServiceNotStarting: return "A thread for the new service could not be created."; case NERR_AlreadyLoggedOn: return "This workstation is already logged on to the local-area network."; case NERR_NotLoggedOn: return "The workstation is not logged on to the local-area network."; case NERR_BadUsername: return "The user name or group name parameter is invalid."; case NERR_BadPassword: return "The password parameter is invalid."; case NERR_UnableToAddName_W: return "@W The logon processor did not add the message alias."; case NERR_UnableToAddName_F: return "The logon processor did not add the message alias."; case NERR_UnableToDelName_W: return "@W The logoff processor did not delete the message alias."; case NERR_UnableToDelName_F: return "The logoff processor did not delete the message alias."; case NERR_LogonsPaused: return "Network logons are paused."; case NERR_LogonServerConflict: return "A centralized logon-server conflict occurred."; case NERR_LogonNoUserPath: return "The server is configured without a valid user path."; case NERR_LogonScriptError: return "An error occurred while loading or running the logon script."; case NERR_StandaloneLogon: return "The logon server was not specified. Your computer will be logged on as STANDALONE."; case NERR_LogonServerNotFound: return "The logon server could not be found."; case NERR_LogonDomainExists: return "There is already a logon domain for this computer."; case NERR_NonValidatedLogon: return "The logon server could not validate the logon."; case NERR_ACFNotFound: return "The security database could not be found."; case NERR_GroupNotFound: return "The group name could not be found."; case NERR_UserNotFound: return "The user name could not be found."; case NERR_ResourceNotFound: return "The resource name could not be found."; case NERR_GroupExists: return "The group already exists."; case NERR_UserExists: return "The user account already exists."; case NERR_ResourceExists: return "The resource permission list already exists."; case NERR_NotPrimary: return "This operation is only allowed on the primary domain controller of the domain."; case NERR_ACFNotLoaded: return "The security database has not been started."; case NERR_ACFNoRoom: return "There are too many names in the user accounts database."; case NERR_ACFFileIOFail: return "A disk I/O failure occurred."; case NERR_ACFTooManyLists: return "The limit of 64 entries per resource was exceeded."; case NERR_UserLogon: return "Deleting a user with a session is not allowed."; case NERR_ACFNoParent: return "The parent directory could not be located."; case NERR_CanNotGrowSegment: return "Unable to add to the security database session cache segment."; case NERR_SpeGroupOp: return "This operation is not allowed on this special group."; case NERR_NotInCache: return "This user is not cached in user accounts database session cache."; case NERR_UserInGroup: return "The user already belongs to this group."; case NERR_UserNotInGroup: return "The user does not belong to this group."; case NERR_AccountUndefined: return "This user account is undefined."; case NERR_AccountExpired: return "This user account has expired."; case NERR_InvalidWorkstation: return "The user is not allowed to log on from this workstation."; case NERR_InvalidLogonHours: return "The user is not allowed to log on at this time."; case NERR_PasswordExpired: return "The password of this user has expired."; case NERR_PasswordCantChange: return "The password of this user cannot change."; case NERR_PasswordHistConflict: return "This password cannot be used now."; case NERR_PasswordTooShort: return "The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements."; case NERR_PasswordTooRecent: return "The password of this user is too recent to change."; case NERR_InvalidDatabase: return "The security database is corrupted."; case NERR_DatabaseUpToDate: return "No updates are necessary to this replicant network/local security database."; case NERR_SyncRequired: return "This replicant database is outdated; synchronization is required."; case NERR_UseNotFound: return "The network connection could not be found."; case NERR_BadAsgType: return "This asg_type is invalid."; case NERR_DeviceIsShared: return "This device is currently being shared."; case NERR_NoComputerName: return "The computer name could not be added as a message alias. The name may already exist on the network."; case NERR_MsgAlreadyStarted: return "The Messenger service is already started."; case NERR_MsgInitFailed: return "The Messenger service failed to start."; case NERR_NameNotFound: return "The message alias could not be found on the network."; case NERR_AlreadyForwarded: return "This message alias has already been forwarded."; case NERR_AddForwarded: return "This message alias has been added but is still forwarded."; case NERR_AlreadyExists: return "This message alias already exists locally."; case NERR_TooManyNames: return "The maximum number of added message aliases has been exceeded."; case NERR_DelComputerName: return "The computer name could not be deleted."; case NERR_LocalForward: return "Messages cannot be forwarded back to the same workstation."; case NERR_GrpMsgProcessor: return "An error occurred in the domain message processor."; case NERR_PausedRemote: return "The message was sent, but the recipient has paused the Messenger service."; case NERR_BadReceive: return "The message was sent but not received."; case NERR_NameInUse: return "The message alias is currently in use. Try again later."; case NERR_MsgNotStarted: return "The Messenger service has not been started."; case NERR_NotLocalName: return "The name is not on the local computer."; case NERR_NoForwardName: return "The forwarded message alias could not be found on the network."; case NERR_RemoteFull: return "The message alias table on the remote station is full."; case NERR_NameNotForwarded: return "Messages for this alias are not currently being forwarded."; case NERR_TruncatedBroadcast: return "The broadcast message was truncated."; case NERR_InvalidDevice: return "This is an invalid device name."; case NERR_WriteFault: return "A write fault occurred."; case NERR_DuplicateName: return "A duplicate message alias exists on the network."; case NERR_DeleteLater: return "@W This message alias will be deleted later."; case NERR_IncompleteDel: return "The message alias was not successfully deleted from all networks."; case NERR_MultipleNets: return "This operation is not supported on computers with multiple networks."; case NERR_NetNameNotFound: return "This shared resource does not exist."; case NERR_DeviceNotShared: return "This device is not shared."; case NERR_ClientNameNotFound: return "A session does not exist with that computer name."; case NERR_FileIdNotFound: return "There is not an open file with that identification number."; case NERR_ExecFailure: return "A failure occurred when executing a remote administration command."; case NERR_TmpFile: return "A failure occurred when opening a remote temporary file."; case NERR_TooMuchData: return "The data returned from a remote administration command has been truncated to 64K."; case NERR_DeviceShareConflict: return "This device cannot be shared as both a spooled and a non-spooled resource."; case NERR_BrowserTableIncomplete: return "The information in the list of servers may be incorrect."; case NERR_NotLocalDomain: return "The computer is not active in this domain."; #ifdef NERR_IsDfsShare case NERR_IsDfsShare: return "The share must be removed from the Distributed File System before it can be deleted."; #endif case NERR_DevInvalidOpCode: return "The operation is invalid for this device."; case NERR_DevNotFound: return "This device cannot be shared."; case NERR_DevNotOpen: return "This device was not open."; case NERR_BadQueueDevString: return "This device name list is invalid."; case NERR_BadQueuePriority: return "The queue priority is invalid."; case NERR_NoCommDevs: return "There are no shared communication devices."; case NERR_QueueNotFound: return "The queue you specified does not exist."; case NERR_BadDevString: return "This list of devices is invalid."; case NERR_BadDev: return "The requested device is invalid."; case NERR_InUseBySpooler: return "This device is already in use by the spooler."; case NERR_CommDevInUse: return "This device is already in use as a communication device."; case NERR_InvalidComputer: return "This computer name is invalid."; case NERR_MaxLenExceeded: return "The string and prefix specified are too long."; case NERR_BadComponent: return "This path component is invalid."; case NERR_CantType: return "Could not determine the type of input."; case NERR_TooManyEntries: return "The buffer for types is not big enough."; case NERR_ProfileFileTooBig: return "Profile files cannot exceed 64K."; case NERR_ProfileOffset: return "The start offset is out of range."; case NERR_ProfileCleanup: return "The system cannot delete current connections to network resources."; case NERR_ProfileUnknownCmd: return "The system was unable to parse the command line in this file."; case NERR_ProfileLoadErr: return "An error occurred while loading the profile file."; case NERR_ProfileSaveErr: return "@W Errors occurred while saving the profile file. The profile was partially saved."; case NERR_LogOverflow: return "Log file %1 is full."; case NERR_LogFileChanged: return "This log file has changed between reads."; case NERR_LogFileCorrupt: return "Log file %1 is corrupt."; case NERR_SourceIsDir: return "The source path cannot be a directory."; case NERR_BadSource: return "The source path is illegal."; case NERR_BadDest: return "The destination path is illegal."; case NERR_DifferentServers: return "The source and destination paths are on different servers."; case NERR_RunSrvPaused: return "The Run server you requested is paused."; case NERR_ErrCommRunSrv: return "An error occurred when communicating with a Run server."; case NERR_ErrorExecingGhost: return "An error occurred when starting a background process."; case NERR_ShareNotFound: return "The shared resource you are connected to could not be found."; case NERR_InvalidLana: return "The LAN adapter number is invalid."; case NERR_OpenFiles: return "There are open files on the connection."; case NERR_ActiveConns: return "Active connections still exist."; case NERR_BadPasswordCore: return "This share name or password is invalid."; case NERR_DevInUse: return "The device is being accessed by an active process."; case NERR_LocalDrive: return "The drive letter is in use locally."; case NERR_AlertExists: return "The specified client is already registered for the specified event."; case NERR_TooManyAlerts: return "The alert table is full."; case NERR_NoSuchAlert: return "An invalid or nonexistent alert name was raised."; case NERR_BadRecipient: return "The alert recipient is invalid."; case NERR_AcctLimitExceeded: return "A user's session with this server has been deleted."; case NERR_InvalidLogSeek: return "The log file does not contain the requested record number."; case NERR_BadUasConfig: return "The user accounts database is not configured correctly."; case NERR_InvalidUASOp: return "This operation is not permitted when the Netlogon service is running."; case NERR_LastAdmin: return "This operation is not allowed on the last administrative account."; case NERR_DCNotFound: return "Could not find domain controller for this domain."; case NERR_LogonTrackingError: return "Could not set logon information for this user."; case NERR_NetlogonNotStarted: return "The Netlogon service has not been started."; case NERR_CanNotGrowUASFile: return "Unable to add to the user accounts database."; case NERR_TimeDiffAtDC: return "This server's clock is not synchronized with the primary domain controller's clock."; case NERR_PasswordMismatch: return "A password mismatch has been detected."; case NERR_NoSuchServer: return "The server identification does not specify a valid server."; case NERR_NoSuchSession: return "The session identification does not specify a valid session."; case NERR_NoSuchConnection: return "The connection identification does not specify a valid connection."; case NERR_TooManyServers: return "There is no space for another entry in the table of available servers."; case NERR_TooManySessions: return "The server has reached the maximum number of sessions it supports."; case NERR_TooManyConnections: return "The server has reached the maximum number of connections it supports."; case NERR_TooManyFiles: return "The server cannot open more files because it has reached its maximum number."; case NERR_NoAlternateServers: return "There are no alternate servers registered on this server."; case NERR_TryDownLevel: return "Try down-level (remote admin protocol) version of API instead."; case NERR_UPSDriverNotStarted: return "The UPS driver could not be accessed by the UPS service."; case NERR_UPSInvalidConfig: return "The UPS service is not configured correctly."; case NERR_UPSInvalidCommPort: return "The UPS service could not access the specified Comm Port."; case NERR_UPSSignalAsserted: return "The UPS indicated a line fail or low battery situation. Service not started."; case NERR_UPSShutdownFailed: return "The UPS service failed to perform a system shut down."; case NERR_BadDosRetCode: return "The program below returned an MS-DOS error code:"; case NERR_ProgNeedsExtraMem: return "The program below needs more memory:"; case NERR_BadDosFunction: return "The program below called an unsupported MS-DOS function:"; case NERR_RemoteBootFailed: return "The workstation failed to boot."; case NERR_BadFileCheckSum: return "The file below is corrupt."; case NERR_NoRplBootSystem: return "No loader is specified in the boot-block definition file."; case NERR_RplLoadrNetBiosErr: return "NetBIOS returned an error: The NCB and SMB are dumped above."; case NERR_RplLoadrDiskErr: return "A disk I/O error occurred."; case NERR_ImageParamErr: return "Image parameter substitution failed."; case NERR_TooManyImageParams: return "Too many image parameters cross disk sector boundaries."; case NERR_NonDosFloppyUsed: return "The image was not generated from an MS-DOS diskette formatted with /S."; case NERR_RplBootRestart: return "Remote boot will be restarted later."; case NERR_RplSrvrCallFailed: return "The call to the Remoteboot server failed."; case NERR_CantConnectRplSrvr: return "Cannot connect to the Remoteboot server."; case NERR_CantOpenImageFile: return "Cannot open image file on the Remoteboot server."; case NERR_CallingRplSrvr: return "Connecting to the Remoteboot server..."; case NERR_StartingRplBoot: return "Connecting to the Remoteboot server..."; case NERR_RplBootServiceTerm: return "Remote boot service was stopped; check the error log for the cause of the problem."; case NERR_RplBootStartFailed: return "Remote boot startup failed; check the error log for the cause of the problem."; case NERR_RPL_CONNECTED: return "A second connection to a Remoteboot resource is not allowed."; case NERR_BrowserConfiguredToNotRun: return "The browser service was configured with MaintainServerList=No."; case NERR_RplNoAdaptersStarted: return "Service failed to start since none of the network adapters started with this service."; case NERR_RplBadRegistry: return "Service failed to start due to bad startup information in the registry."; case NERR_RplBadDatabase: return "Service failed to start because its database is absent or corrupt."; case NERR_RplRplfilesShare: return "Service failed to start because RPLFILES share is absent."; case NERR_RplNotRplServer: return "Service failed to start because RPLUSER group is absent."; case NERR_RplCannotEnum: return "Cannot enumerate service records."; case NERR_RplWkstaInfoCorrupted: return "Workstation record information has been corrupted."; case NERR_RplWkstaNotFound: return "Workstation record was not found."; case NERR_RplWkstaNameUnavailable: return "Workstation name is in use by some other workstation."; case NERR_RplProfileInfoCorrupted: return "Profile record information has been corrupted."; case NERR_RplProfileNotFound: return "Profile record was not found."; case NERR_RplProfileNameUnavailable: return "Profile name is in use by some other profile."; case NERR_RplProfileNotEmpty: return "There are workstations using this profile."; case NERR_RplConfigInfoCorrupted: return "Configuration record information has been corrupted."; case NERR_RplConfigNotFound: return "Configuration record was not found."; case NERR_RplAdapterInfoCorrupted: return "Adapter ID record information has been corrupted."; case NERR_RplInternal: return "An internal service error has occurred."; case NERR_RplVendorInfoCorrupted: return "Vendor ID record information has been corrupted."; case NERR_RplBootInfoCorrupted: return "Boot block record information has been corrupted."; case NERR_RplWkstaNeedsUserAcct: return "The user account for this workstation record is missing."; case NERR_RplNeedsRPLUSERAcct: return "The RPLUSER local group could not be found."; case NERR_RplBootNotFound: return "Boot block record was not found."; case NERR_RplIncompatibleProfile: return "Chosen profile is incompatible with this workstation."; case NERR_RplAdapterNameUnavailable: return "Chosen network adapter ID is in use by some other workstation."; case NERR_RplConfigNotEmpty: return "There are profiles using this configuration."; case NERR_RplBootInUse: return "There are workstations, profiles, or configurations using this boot block."; case NERR_RplBackupDatabase: return "Service failed to backup Remoteboot database."; case NERR_RplAdapterNotFound: return "Adapter record was not found."; case NERR_RplVendorNotFound: return "Vendor record was not found."; case NERR_RplVendorNameUnavailable: return "Vendor name is in use by some other vendor record."; case NERR_RplBootNameUnavailable: return "(boot name, vendor ID) is in use by some other boot block record."; case NERR_RplConfigNameUnavailable: return "Configuration name is in use by some other configuration."; case NERR_DfsInternalCorruption: return "The internal database maintained by the Dfs service is corrupt."; case NERR_DfsVolumeDataCorrupt: return "One of the records in the internal Dfs database is corrupt."; case NERR_DfsNoSuchVolume: return "There is no DFS name whose entry path matches the input Entry Path."; case NERR_DfsVolumeAlreadyExists: return "A root or link with the given name already exists."; case NERR_DfsAlreadyShared: return "The server share specified is already shared in the Dfs."; case NERR_DfsNoSuchShare: return "The indicated server share does not support the indicated DFS namespace."; case NERR_DfsNotALeafVolume: return "The operation is not valid on this portion of the namespace."; case NERR_DfsLeafVolume: return "The operation is not valid on this portion of the namespace."; case NERR_DfsVolumeHasMultipleServers: return "The operation is ambiguous because the link has multiple servers."; case NERR_DfsCantCreateJunctionPoint: return "Unable to create a link."; case NERR_DfsServerNotDfsAware: return "The server is not Dfs Aware."; case NERR_DfsBadRenamePath: return "The specified rename target path is invalid."; case NERR_DfsVolumeIsOffline: return "The specified DFS link is offline."; case NERR_DfsNoSuchServer: return "The specified server is not a server for this link."; case NERR_DfsCyclicalName: return "A cycle in the Dfs name was detected."; case NERR_DfsNotSupportedInServerDfs: return "The operation is not supported on a server-based Dfs."; case NERR_DfsDuplicateService: return "This link is already supported by the specified server-share."; case NERR_DfsCantRemoveLastServerShare: return "Can't remove the last server-share supporting this root or link."; case NERR_DfsVolumeIsInterDfs: return "The operation is not supported for an Inter-DFS link."; case NERR_DfsInconsistent: return "The internal state of the Dfs Service has become inconsistent."; case NERR_DfsServerUpgraded: return "The Dfs Service has been installed on the specified server."; case NERR_DfsDataIsIdentical: return "The Dfs data being reconciled is identical."; case NERR_DfsCantRemoveDfsRoot: return "The DFS root cannot be deleted. Uninstall DFS if required."; case NERR_DfsChildOrParentInDfs: return "A child or parent directory of the share is already in a Dfs."; case NERR_DfsInternalError: return "Dfs internal error."; /* the following are not defined in mingw */ #if 0 case NERR_SetupAlreadyJoined: return "This machine is already joined to a domain."; case NERR_SetupNotJoined: return "This machine is not currently joined to a domain."; case NERR_SetupDomainController: return "This machine is a domain controller and cannot be unjoined from a domain."; case NERR_DefaultJoinRequired: return "The destination domain controller does not support creating machine accounts in OUs."; case NERR_InvalidWorkgroupName: return "The specified workgroup name is invalid."; case NERR_NameUsesIncompatibleCodePage: return "The specified computer name is incompatible with the default language used on the domain controller."; case NERR_ComputerAccountNotFound: return "The specified computer account could not be found."; case NERR_PersonalSku: return "This version of Windows cannot be joined to a domain."; case NERR_PasswordMustChange: return "The password must change at the next logon."; case NERR_AccountLockedOut: return "The account is locked out."; case NERR_PasswordTooLong: return "The password is too long."; case NERR_PasswordNotComplexEnough: return "The password does not meet the complexity policy."; case NERR_PasswordFilterError: return "The password does not meet the requirements of the password filter DLLs."; #endif } msg = strerror (error_number); if (msg == NULL) msg = "unknown"; return msg; #endif //DBUS_WINCE } /** * Get a printable string describing the command used to execute * the process with pid. This string should only be used for * informative purposes such as logging; it may not be trusted. * * The command is guaranteed to be printable ASCII and no longer * than max_len. * * @param pid Process id * @param str Append command to this string * @param max_len Maximum length of returned command * @param error return location for errors * @returns #FALSE on error */ dbus_bool_t _dbus_command_for_pid (unsigned long pid, DBusString *str, int max_len, DBusError *error) { // FIXME return FALSE; } /* * replaces the term DBUS_PREFIX in configure_time_path by the * current dbus installation directory. On unix this function is a noop * * @param configure_time_path * @return real path */ const char * _dbus_replace_install_prefix (const char *configure_time_path) { #ifndef DBUS_PREFIX return configure_time_path; #else static char retval[1000]; static char runtime_prefix[1000]; int len = 1000; int i; if (!configure_time_path) return NULL; if ((!_dbus_get_install_root(runtime_prefix, len) || strncmp (configure_time_path, DBUS_PREFIX "/", strlen (DBUS_PREFIX) + 1))) { strncpy (retval, configure_time_path, sizeof (retval) - 1); /* strncpy does not guarantee to 0-terminate the string */ retval[sizeof (retval) - 1] = '\0'; } else { size_t remaining; strncpy (retval, runtime_prefix, sizeof (retval) - 1); retval[sizeof (retval) - 1] = '\0'; remaining = sizeof (retval) - 1 - strlen (retval); strncat (retval, configure_time_path + strlen (DBUS_PREFIX) + 1, remaining); } /* Somehow, in some situations, backslashes get collapsed in the string. * Since windows C library accepts both forward and backslashes as * path separators, convert all backslashes to forward slashes. */ for(i = 0; retval[i] != '\0'; i++) { if(retval[i] == '\\') retval[i] = '/'; } return retval; #endif } /** * return the relocated DATADIR * * @returns relocated DATADIR static string */ static const char * _dbus_windows_get_datadir (void) { return _dbus_replace_install_prefix(DBUS_DATADIR); } #undef DBUS_DATADIR #define DBUS_DATADIR _dbus_windows_get_datadir () #define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" #define DBUS_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services" /** * Returns the standard directories for a session bus to look for service * activation files * * On Windows this should be data directories: * * %CommonProgramFiles%/dbus * * and * * relocated DBUS_DATADIR * * @param dirs the directory list we are returning * @returns #FALSE on OOM */ dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs) { const char *common_progs; DBusString servicedir_path; if (!_dbus_string_init (&servicedir_path)) return FALSE; #ifdef DBUS_WINCE { /* On Windows CE, we adjust datadir dynamically to installation location. */ const char *data_dir = _dbus_getenv ("DBUS_DATADIR"); if (data_dir != NULL) { if (!_dbus_string_append (&servicedir_path, data_dir)) goto oom; if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR)) goto oom; } } #else /* the code for accessing services requires absolute base pathes in case DBUS_DATADIR is relative make it absolute */ #ifdef DBUS_WIN { DBusString p; _dbus_string_init_const (&p, DBUS_DATADIR); if (!_dbus_path_is_absolute (&p)) { char install_root[1000]; if (_dbus_get_install_root (install_root, sizeof(install_root))) if (!_dbus_string_append (&servicedir_path, install_root)) goto oom; } } #endif if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR)) goto oom; if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR)) goto oom; #endif common_progs = _dbus_getenv ("CommonProgramFiles"); if (common_progs != NULL) { if (!_dbus_string_append (&servicedir_path, common_progs)) goto oom; if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR)) goto oom; } if (!_dbus_split_paths_and_append (&servicedir_path, DBUS_STANDARD_SESSION_SERVICEDIR, dirs)) goto oom; _dbus_string_free (&servicedir_path); return TRUE; oom: _dbus_string_free (&servicedir_path); return FALSE; } /** * Returns the standard directories for a system bus to look for service * activation files * * On UNIX this should be the standard xdg freedesktop.org data directories: * * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} * * and * * DBUS_DATADIR * * On Windows there is no system bus and this function can return nothing. * * @param dirs the directory list we are returning * @returns #FALSE on OOM */ dbus_bool_t _dbus_get_standard_system_servicedirs (DBusList **dirs) { *dirs = NULL; return TRUE; } static dbus_bool_t _dbus_get_config_file_name (DBusString *str, const char *basename) { DBusString tmp; if (!_dbus_string_append (str, _dbus_windows_get_datadir ())) return FALSE; _dbus_string_init_const (&tmp, "dbus-1"); if (!_dbus_concat_dir_and_file (str, &tmp)) return FALSE; _dbus_string_init_const (&tmp, basename); if (!_dbus_concat_dir_and_file (str, &tmp)) return FALSE; return TRUE; } /** * Append the absolute path of the system.conf file * (there is no system bus on Windows so this can just * return FALSE and print a warning or something) * * @param str the string to append to * @returns #FALSE if no memory */ dbus_bool_t _dbus_append_system_config_file (DBusString *str) { return _dbus_get_config_file_name(str, "system.conf"); } /** * Append the absolute path of the session.conf file. * * @param str the string to append to * @returns #FALSE if no memory */ dbus_bool_t _dbus_append_session_config_file (DBusString *str) { return _dbus_get_config_file_name(str, "session.conf"); } dbus-1.10.6/dbus/dbus-socket-set-epoll.c0000644000175000017500000002240612602773110017767 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-socket-set-epoll.c - a socket set implemented via Linux epoll(4) * * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * */ #include #include "dbus-socket-set.h" #include #include #ifndef __linux__ # error This file is for Linux epoll(4) #endif #include #include #include #include #ifndef DOXYGEN_SHOULD_SKIP_THIS typedef struct { DBusSocketSet parent; int epfd; } DBusSocketSetEpoll; static inline DBusSocketSetEpoll * socket_set_epoll_cast (DBusSocketSet *set) { _dbus_assert (set->cls == &_dbus_socket_set_epoll_class); return (DBusSocketSetEpoll *) set; } /* this is safe to call on a partially-allocated socket set */ static void socket_set_epoll_free (DBusSocketSet *set) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); if (self == NULL) return; if (self->epfd != -1) close (self->epfd); dbus_free (self); } DBusSocketSet * _dbus_socket_set_epoll_new (void) { DBusSocketSetEpoll *self; self = dbus_new0 (DBusSocketSetEpoll, 1); if (self == NULL) return NULL; self->parent.cls = &_dbus_socket_set_epoll_class; self->epfd = epoll_create1 (EPOLL_CLOEXEC); if (self->epfd == -1) { int flags; /* the size hint is ignored unless you have a rather old kernel, * but must be positive on some versions, so just pick something * arbitrary; it's a hint, not a limit */ self->epfd = epoll_create (42); flags = fcntl (self->epfd, F_GETFD, 0); if (flags != -1) fcntl (self->epfd, F_SETFD, flags | FD_CLOEXEC); } if (self->epfd == -1) { socket_set_epoll_free ((DBusSocketSet *) self); return NULL; } return (DBusSocketSet *) self; } static uint32_t watch_flags_to_epoll_events (unsigned int flags) { uint32_t events = 0; if (flags & DBUS_WATCH_READABLE) events |= EPOLLIN; if (flags & DBUS_WATCH_WRITABLE) events |= EPOLLOUT; return events; } static unsigned int epoll_events_to_watch_flags (uint32_t events) { short flags = 0; if (events & EPOLLIN) flags |= DBUS_WATCH_READABLE; if (events & EPOLLOUT) flags |= DBUS_WATCH_WRITABLE; if (events & EPOLLHUP) flags |= DBUS_WATCH_HANGUP; if (events & EPOLLERR) flags |= DBUS_WATCH_ERROR; return flags; } static dbus_bool_t socket_set_epoll_add (DBusSocketSet *set, DBusPollable fd, unsigned int flags, dbus_bool_t enabled) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); struct epoll_event event; int err; event.data.fd = fd; if (enabled) { event.events = watch_flags_to_epoll_events (flags); } else { /* We need to add *something* to reserve space in the kernel's data * structures: see socket_set_epoll_disable for more details */ event.events = EPOLLET; } if (epoll_ctl (self->epfd, EPOLL_CTL_ADD, fd, &event) == 0) return TRUE; /* Anything except ENOMEM, ENOSPC means we have an internal error. */ err = errno; switch (err) { case ENOMEM: case ENOSPC: /* be silent: this is basically OOM, which our callers are expected * to cope with */ break; case EBADF: _dbus_warn ("Bad fd %d\n", fd); break; case EEXIST: _dbus_warn ("fd %d added and then added again\n", fd); break; default: _dbus_warn ("Misc error when trying to watch fd %d: %s\n", fd, strerror (err)); break; } return FALSE; } static void socket_set_epoll_enable (DBusSocketSet *set, DBusPollable fd, unsigned int flags) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); struct epoll_event event; int err; event.data.fd = fd; event.events = watch_flags_to_epoll_events (flags); if (epoll_ctl (self->epfd, EPOLL_CTL_MOD, fd, &event) == 0) return; err = errno; /* Enabling a file descriptor isn't allowed to fail, even for OOM, so we * do our best to avoid all of these. */ switch (err) { case EBADF: _dbus_warn ("Bad fd %d\n", fd); break; case ENOENT: _dbus_warn ("fd %d enabled before it was added\n", fd); break; case ENOMEM: _dbus_warn ("Insufficient memory to change watch for fd %d\n", fd); break; default: _dbus_warn ("Misc error when trying to watch fd %d: %s\n", fd, strerror (err)); break; } } static void socket_set_epoll_disable (DBusSocketSet *set, DBusPollable fd) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); struct epoll_event event; int err; /* The naive thing to do would be EPOLL_CTL_DEL, but that'll probably * free resources in the kernel. When we come to do socket_set_epoll_enable, * there might not be enough resources to bring it back! * * The next idea you might have is to set the flags to 0. However, events * always trigger on EPOLLERR and EPOLLHUP, even if libdbus isn't actually * delivering them to a DBusWatch. Because epoll is level-triggered by * default, we'll busy-loop on an unhandled error or hangup; not good. * * So, let's set it to be edge-triggered: then the worst case is that * we return from poll immediately on one iteration, ignore it because no * watch is enabled, then go back to normal. When we re-enable a watch * we'll switch back to level-triggered and be notified again (verified to * work on 2.6.32). Compile this file with -DTEST_BEHAVIOUR_OF_EPOLLET for * test code. */ event.data.fd = fd; event.events = EPOLLET; if (epoll_ctl (self->epfd, EPOLL_CTL_MOD, fd, &event) == 0) return; err = errno; _dbus_warn ("Error when trying to watch fd %d: %s\n", fd, strerror (err)); } static void socket_set_epoll_remove (DBusSocketSet *set, DBusPollable fd) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); int err; /* Kernels < 2.6.9 require a non-NULL struct pointer, even though its * contents are ignored */ struct epoll_event dummy = { 0 }; if (epoll_ctl (self->epfd, EPOLL_CTL_DEL, fd, &dummy) == 0) return; err = errno; _dbus_warn ("Error when trying to remove fd %d: %s\n", fd, strerror (err)); } /* Optimally, this should be the same as in DBusLoop: we use it to translate * between struct epoll_event and DBusSocketEvent without allocating heap * memory. */ #define N_STACK_DESCRIPTORS 64 static int socket_set_epoll_poll (DBusSocketSet *set, DBusSocketEvent *revents, int max_events, int timeout_ms) { DBusSocketSetEpoll *self = socket_set_epoll_cast (set); struct epoll_event events[N_STACK_DESCRIPTORS]; int n_ready; int i; _dbus_assert (max_events > 0); n_ready = epoll_wait (self->epfd, events, MIN (_DBUS_N_ELEMENTS (events), max_events), timeout_ms); if (n_ready <= 0) return n_ready; for (i = 0; i < n_ready; i++) { revents[i].fd = events[i].data.fd; revents[i].flags = epoll_events_to_watch_flags (events[i].events); } return n_ready; } DBusSocketSetClass _dbus_socket_set_epoll_class = { socket_set_epoll_free, socket_set_epoll_add, socket_set_epoll_remove, socket_set_epoll_enable, socket_set_epoll_disable, socket_set_epoll_poll }; #ifdef TEST_BEHAVIOUR_OF_EPOLLET /* usage: cat /dev/null | ./epoll * * desired output: * ctl ADD: 0 * wait for HUP, edge-triggered: 1 * wait for HUP again: 0 * ctl MOD: 0 * wait for HUP: 1 */ #include #include int main (void) { struct epoll_event input; struct epoll_event output; int epfd = epoll_create1 (EPOLL_CLOEXEC); int fd = 0; /* stdin */ int ret; input.events = EPOLLHUP | EPOLLET; ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &input); printf ("ctl ADD: %d\n", ret); ret = epoll_wait (epfd, &output, 1, -1); printf ("wait for HUP, edge-triggered: %d\n", ret); ret = epoll_wait (epfd, &output, 1, 1); printf ("wait for HUP again: %d\n", ret); input.events = EPOLLHUP; ret = epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &input); printf ("ctl MOD: %d\n", ret); ret = epoll_wait (epfd, &output, 1, -1); printf ("wait for HUP: %d\n", ret); return 0; } #endif /* TEST_BEHAVIOUR_OF_EPOLLET */ #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ dbus-1.10.6/dbus/dbus-spawn.c0000644000175000017500000013377712602773110015743 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-spawn.c Wrapper around fork/exec * * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-spawn.h" #include "dbus-sysdeps-unix.h" #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-protocol.h" #include #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_SYSTEMD #ifdef HAVE_SYSLOG_H #include #endif #include #endif extern char **environ; /** * @addtogroup DBusInternalsUtils * @{ */ /* * I'm pretty sure this whole spawn file could be made simpler, * if you thought about it a bit. */ /** * Enumeration for status of a read() */ typedef enum { READ_STATUS_OK, /**< Read succeeded */ READ_STATUS_ERROR, /**< Some kind of error */ READ_STATUS_EOF /**< EOF returned */ } ReadStatus; static ReadStatus read_ints (int fd, int *buf, int n_ints_in_buf, int *n_ints_read, DBusError *error) { size_t bytes = 0; ReadStatus retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = READ_STATUS_OK; while (TRUE) { ssize_t chunk; size_t to_read; to_read = sizeof (int) * n_ints_in_buf - bytes; if (to_read == 0) break; again: chunk = read (fd, ((char*)buf) + bytes, to_read); if (chunk < 0 && errno == EINTR) goto again; if (chunk < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to read from child pipe (%s)", _dbus_strerror (errno)); retval = READ_STATUS_ERROR; break; } else if (chunk == 0) { retval = READ_STATUS_EOF; break; /* EOF */ } else /* chunk > 0 */ bytes += chunk; } *n_ints_read = (int)(bytes / sizeof(int)); return retval; } static ReadStatus read_pid (int fd, pid_t *buf, DBusError *error) { size_t bytes = 0; ReadStatus retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = READ_STATUS_OK; while (TRUE) { ssize_t chunk; size_t to_read; to_read = sizeof (pid_t) - bytes; if (to_read == 0) break; again: chunk = read (fd, ((char*)buf) + bytes, to_read); if (chunk < 0 && errno == EINTR) goto again; if (chunk < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to read from child pipe (%s)", _dbus_strerror (errno)); retval = READ_STATUS_ERROR; break; } else if (chunk == 0) { retval = READ_STATUS_EOF; break; /* EOF */ } else /* chunk > 0 */ bytes += chunk; } return retval; } /* The implementation uses an intermediate child between the main process * and the grandchild. The grandchild is our spawned process. The intermediate * child is a babysitter process; it keeps track of when the grandchild * exits/crashes, and reaps the grandchild. * * We automatically reap the babysitter process, killing it if necessary, * when the DBusBabysitter's refcount goes to zero. * * Processes: * * main process * | fork() A * \- babysitter * | fork () B * \- grandchild --> exec --> spawned process * * IPC: * child_err_report_pipe * /-----------<---------<--------------\ * | ^ * v | * main process babysitter grandchild * ^ ^ * v v * \-------<->-------/ * babysitter_pipe * * child_err_report_pipe is genuinely a pipe. * The READ_END (also called error_pipe_from_child) is used in the main * process. The WRITE_END (also called child_err_report_fd) is used in * the grandchild process. * * On failure, the grandchild process sends CHILD_EXEC_FAILED + errno. * On success, the pipe just closes (because it's close-on-exec) without * sending any bytes. * * babysitter_pipe is mis-named: it's really a bidirectional socketpair. * The [0] end (also called socket_to_babysitter) is used in the main * process, the [1] end (also called parent_pipe) is used in the babysitter. * * If the fork() labelled B in the diagram above fails, the babysitter sends * CHILD_FORK_FAILED + errno. * On success, the babysitter sends CHILD_PID + the grandchild's pid. * On SIGCHLD, the babysitter sends CHILD_EXITED + the exit status. * The main process doesn't explicitly send anything, but when it exits, * the babysitter gets POLLHUP or POLLERR. */ /* Messages from children to parents */ enum { CHILD_EXITED, /* This message is followed by the exit status int */ CHILD_FORK_FAILED, /* Followed by errno */ CHILD_EXEC_FAILED, /* Followed by errno */ CHILD_PID /* Followed by pid_t */ }; /** * Babysitter implementation details */ struct DBusBabysitter { int refcount; /**< Reference count */ char *log_name; /**< the name under which to log messages about this process being spawned */ DBusSocket socket_to_babysitter; /**< Connection to the babysitter process */ int error_pipe_from_child; /**< Connection to the process that does the exec() */ pid_t sitter_pid; /**< PID Of the babysitter */ pid_t grandchild_pid; /**< PID of the grandchild */ DBusWatchList *watches; /**< Watches */ DBusWatch *error_watch; /**< Error pipe watch */ DBusWatch *sitter_watch; /**< Sitter pipe watch */ DBusBabysitterFinishedFunc finished_cb; void *finished_data; int errnum; /**< Error number */ int status; /**< Exit status code */ unsigned int have_child_status : 1; /**< True if child status has been reaped */ unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */ unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */ }; static DBusBabysitter* _dbus_babysitter_new (void) { DBusBabysitter *sitter; sitter = dbus_new0 (DBusBabysitter, 1); if (sitter == NULL) return NULL; sitter->refcount = 1; sitter->socket_to_babysitter.fd = -1; sitter->error_pipe_from_child = -1; sitter->sitter_pid = -1; sitter->grandchild_pid = -1; sitter->watches = _dbus_watch_list_new (); if (sitter->watches == NULL) goto failed; return sitter; failed: _dbus_babysitter_unref (sitter); return NULL; } /** * Increment the reference count on the babysitter object. * * @param sitter the babysitter * @returns the babysitter */ DBusBabysitter * _dbus_babysitter_ref (DBusBabysitter *sitter) { _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount += 1; return sitter; } static void close_socket_to_babysitter (DBusBabysitter *sitter); static void close_error_pipe_from_child (DBusBabysitter *sitter); /** * Decrement the reference count on the babysitter object. * When the reference count of the babysitter object reaches * zero, the babysitter is killed and the child that was being * babysat gets emancipated. * * @param sitter the babysitter */ void _dbus_babysitter_unref (DBusBabysitter *sitter) { _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount -= 1; if (sitter->refcount == 0) { /* If we haven't forked other babysitters * since this babysitter and socket were * created then this close will cause the * babysitter to wake up from poll with * a hangup and then the babysitter will * quit itself. */ close_socket_to_babysitter (sitter); close_error_pipe_from_child (sitter); if (sitter->sitter_pid > 0) { int status; int ret; /* It's possible the babysitter died on its own above * from the close, or was killed randomly * by some other process, so first try to reap it */ ret = waitpid (sitter->sitter_pid, &status, WNOHANG); /* If we couldn't reap the child then kill it, and * try again */ if (ret == 0) kill (sitter->sitter_pid, SIGKILL); if (ret == 0) { do { ret = waitpid (sitter->sitter_pid, &status, 0); } while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR)); } if (ret < 0) { if (errno == ECHILD) _dbus_warn ("Babysitter process not available to be reaped; should not happen\n"); else _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n", errno, _dbus_strerror (errno)); } else { _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n", (long) ret, (long) sitter->sitter_pid); if (WIFEXITED (sitter->status)) _dbus_verbose ("Babysitter exited with status %d\n", WEXITSTATUS (sitter->status)); else if (WIFSIGNALED (sitter->status)) _dbus_verbose ("Babysitter received signal %d\n", WTERMSIG (sitter->status)); else _dbus_verbose ("Babysitter exited abnormally\n"); } sitter->sitter_pid = -1; } if (sitter->watches) _dbus_watch_list_free (sitter->watches); dbus_free (sitter->log_name); dbus_free (sitter); } } static ReadStatus read_data (DBusBabysitter *sitter, int fd) { int what; int got; DBusError error = DBUS_ERROR_INIT; ReadStatus r; r = read_ints (fd, &what, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { switch (what) { case CHILD_EXITED: case CHILD_FORK_FAILED: case CHILD_EXEC_FAILED: { int arg; r = read_ints (fd, &arg, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { if (what == CHILD_EXITED) { /* Do not reset sitter->errnum to 0 here. We get here if * the babysitter reports that the grandchild process has * exited, and there are two ways that can happen: * * 1. grandchild successfully exec()s the desired process, * but then the desired process exits or is terminated * by a signal. The babysitter observes this and reports * CHILD_EXITED. * * 2. grandchild fails to exec() the desired process, * attempts to report the exec() failure (which * we will receive as CHILD_EXEC_FAILED), and then * exits itself (which will prompt the babysitter to * send CHILD_EXITED). We want the CHILD_EXEC_FAILED * to take precedence (and have its errno logged), * which _dbus_babysitter_set_child_exit_error() does. */ sitter->have_child_status = TRUE; sitter->status = arg; _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n", WIFEXITED (sitter->status), WIFSIGNALED (sitter->status), WEXITSTATUS (sitter->status), WTERMSIG (sitter->status)); } else if (what == CHILD_FORK_FAILED) { sitter->have_fork_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum); } else if (what == CHILD_EXEC_FAILED) { sitter->have_exec_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum); } } } break; case CHILD_PID: { pid_t pid = -1; r = read_pid (fd, &pid, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } sitter->grandchild_pid = pid; _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid); } break; default: _dbus_warn ("Unknown message received from babysitter process\n"); break; } } return r; } static void close_socket_to_babysitter (DBusBabysitter *sitter) { _dbus_verbose ("Closing babysitter\n"); if (sitter->sitter_watch != NULL) { _dbus_assert (sitter->watches != NULL); _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch); _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->socket_to_babysitter.fd >= 0) { _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter.fd = -1; } } static void close_error_pipe_from_child (DBusBabysitter *sitter) { _dbus_verbose ("Closing child error\n"); if (sitter->error_watch != NULL) { _dbus_assert (sitter->watches != NULL); _dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch); _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; } if (sitter->error_pipe_from_child >= 0) { _dbus_close (sitter->error_pipe_from_child, NULL); sitter->error_pipe_from_child = -1; } } static void handle_babysitter_socket (DBusBabysitter *sitter, int revents) { /* Even if we have POLLHUP, we want to keep reading * data until POLLIN goes away; so this function only * looks at HUP/ERR if no IN is set. */ if (revents & _DBUS_POLLIN) { _dbus_verbose ("Reading data from babysitter\n"); if (read_data (sitter, sitter->socket_to_babysitter.fd) != READ_STATUS_OK) close_socket_to_babysitter (sitter); } else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) { close_socket_to_babysitter (sitter); } } static void handle_error_pipe (DBusBabysitter *sitter, int revents) { if (revents & _DBUS_POLLIN) { _dbus_verbose ("Reading data from child error\n"); if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK) close_error_pipe_from_child (sitter); } else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) { close_error_pipe_from_child (sitter); } } /* returns whether there were any poll events handled */ static dbus_bool_t babysitter_iteration (DBusBabysitter *sitter, dbus_bool_t block) { DBusPollFD fds[2]; int i; dbus_bool_t descriptors_ready; descriptors_ready = FALSE; i = 0; if (sitter->error_pipe_from_child >= 0) { fds[i].fd = sitter->error_pipe_from_child; fds[i].events = _DBUS_POLLIN; fds[i].revents = 0; ++i; } if (sitter->socket_to_babysitter.fd >= 0) { fds[i].fd = sitter->socket_to_babysitter.fd; fds[i].events = _DBUS_POLLIN; fds[i].revents = 0; ++i; } if (i > 0) { int ret; do { ret = _dbus_poll (fds, i, 0); } while (ret < 0 && errno == EINTR); if (ret == 0 && block) { do { ret = _dbus_poll (fds, i, -1); } while (ret < 0 && errno == EINTR); } if (ret > 0) { descriptors_ready = TRUE; while (i > 0) { --i; if (fds[i].fd == sitter->error_pipe_from_child) handle_error_pipe (sitter, fds[i].revents); else if (fds[i].fd == sitter->socket_to_babysitter.fd) handle_babysitter_socket (sitter, fds[i].revents); } } } return descriptors_ready; } /** * Macro returns #TRUE if the babysitter still has live sockets open to the * babysitter child or the grandchild. */ #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter.fd >= 0 || (sitter)->error_pipe_from_child >= 0) /** * Blocks until the babysitter process gives us the PID of the spawned grandchild, * then kills the spawned grandchild. * * @param sitter the babysitter object */ void _dbus_babysitter_kill_child (DBusBabysitter *sitter) { /* be sure we have the PID of the child */ while (LIVE_CHILDREN (sitter) && sitter->grandchild_pid == -1) babysitter_iteration (sitter, TRUE); _dbus_verbose ("Got child PID %ld for killing\n", (long) sitter->grandchild_pid); if (sitter->grandchild_pid == -1) return; /* child is already dead, or we're so hosed we'll never recover */ kill (sitter->grandchild_pid, SIGKILL); } /** * Checks whether the child has exited, without blocking. * * @param sitter the babysitter */ dbus_bool_t _dbus_babysitter_get_child_exited (DBusBabysitter *sitter) { /* Be sure we're up-to-date */ while (LIVE_CHILDREN (sitter) && babysitter_iteration (sitter, FALSE)) ; /* We will have exited the babysitter when the child has exited */ return sitter->socket_to_babysitter.fd < 0; } /** * Gets the exit status of the child. We do this so implementation specific * detail is not cluttering up dbus, for example the system launcher code. * This can only be called if the child has exited, i.e. call * _dbus_babysitter_get_child_exited(). It returns FALSE if the child * did not return a status code, e.g. because the child was signaled * or we failed to ever launch the child in the first place. * * @param sitter the babysitter * @param status the returned status code * @returns #FALSE on failure */ dbus_bool_t _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, int *status) { if (!_dbus_babysitter_get_child_exited (sitter)) _dbus_assert_not_reached ("Child has not exited"); if (!sitter->have_child_status || !(WIFEXITED (sitter->status))) return FALSE; *status = WEXITSTATUS (sitter->status); return TRUE; } /** * Sets the #DBusError with an explanation of why the spawned * child process exited (on a signal, or whatever). If * the child process has not exited, does nothing (error * will remain unset). * * @param sitter the babysitter * @param error an error to fill in */ void _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, DBusError *error) { if (!_dbus_babysitter_get_child_exited (sitter)) return; /* Note that if exec fails, we will also get a child status * from the babysitter saying the child exited, * so we need to give priority to the exec error */ if (sitter->have_exec_errnum) { dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "Failed to execute program %s: %s", sitter->log_name, _dbus_strerror (sitter->errnum)); } else if (sitter->have_fork_errnum) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Failed to fork a new process %s: %s", sitter->log_name, _dbus_strerror (sitter->errnum)); } else if (sitter->have_child_status) { if (WIFEXITED (sitter->status)) dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, "Process %s exited with status %d", sitter->log_name, WEXITSTATUS (sitter->status)); else if (WIFSIGNALED (sitter->status)) dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED, "Process %s received signal %d", sitter->log_name, WTERMSIG (sitter->status)); else dbus_set_error (error, DBUS_ERROR_FAILED, "Process %s exited abnormally", sitter->log_name); } else { dbus_set_error (error, DBUS_ERROR_FAILED, "Process %s exited, reason unknown", sitter->log_name); } } /** * Sets watch functions to notify us when the * babysitter object needs to read/write file descriptors. * * @param sitter the babysitter * @param add_function function to begin monitoring a new descriptor. * @param remove_function function to stop monitoring a descriptor. * @param toggled_function function to notify when the watch is enabled/disabled * @param data data to pass to add_function and remove_function. * @param free_data_function function to be called to free the data. * @returns #FALSE on failure (no memory) */ dbus_bool_t _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { return _dbus_watch_list_set_functions (sitter->watches, add_function, remove_function, toggled_function, data, free_data_function); } static dbus_bool_t handle_watch (DBusWatch *watch, unsigned int condition, void *data) { DBusBabysitter *sitter = _dbus_babysitter_ref (data); int revents; int fd; revents = 0; if (condition & DBUS_WATCH_READABLE) revents |= _DBUS_POLLIN; if (condition & DBUS_WATCH_ERROR) revents |= _DBUS_POLLERR; if (condition & DBUS_WATCH_HANGUP) revents |= _DBUS_POLLHUP; fd = dbus_watch_get_socket (watch); if (fd == sitter->error_pipe_from_child) handle_error_pipe (sitter, revents); else if (fd == sitter->socket_to_babysitter.fd) handle_babysitter_socket (sitter, revents); while (LIVE_CHILDREN (sitter) && babysitter_iteration (sitter, FALSE)) ; /* fd.o #32992: if the handle_* methods closed their sockets, they previously * didn't always remove the watches. Check that we don't regress. */ _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL); _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL); if (_dbus_babysitter_get_child_exited (sitter) && sitter->finished_cb != NULL) { sitter->finished_cb (sitter, sitter->finished_data); sitter->finished_cb = NULL; } _dbus_babysitter_unref (sitter); return TRUE; } /** Helps remember which end of the pipe is which */ #define READ_END 0 /** Helps remember which end of the pipe is which */ #define WRITE_END 1 /* Avoids a danger in re-entrant situations (calling close() * on a file descriptor twice, and another module has * re-opened it since the first close). * * This previously claimed to be relevant for threaded situations, but by * trivial inspection, it is not thread-safe. It doesn't actually * matter, since this module is only used in the -util variant of the * library, which is only used in single-threaded situations. */ static int close_and_invalidate (int *fd) { int ret; if (*fd < 0) return -1; else { ret = _dbus_close (*fd, NULL); *fd = -1; } return ret; } static dbus_bool_t make_pipe (int p[2], DBusError *error) { int retval; #ifdef HAVE_PIPE2 dbus_bool_t cloexec_done; retval = pipe2 (p, O_CLOEXEC); cloexec_done = retval >= 0; /* Check if kernel seems to be too old to know pipe2(). We assume that if pipe2 is available, O_CLOEXEC is too. */ if (retval < 0 && errno == ENOSYS) #endif { retval = pipe(p); } _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (retval < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to create pipe for communicating with child process (%s)", _dbus_strerror (errno)); return FALSE; } #ifdef HAVE_PIPE2 if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec (p[0]); _dbus_fd_set_close_on_exec (p[1]); } return TRUE; } static void do_write (int fd, const void *buf, size_t count) { size_t bytes_written; int ret; bytes_written = 0; again: ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written); if (ret < 0) { if (errno == EINTR) goto again; else { _dbus_warn ("Failed to write data to pipe!\n"); exit (1); /* give up, we suck */ } } else bytes_written += ret; if (bytes_written < count) goto again; } static void write_err_and_exit (int fd, int msg) { int en = errno; do_write (fd, &msg, sizeof (msg)); do_write (fd, &en, sizeof (en)); exit (1); } static void write_pid (int fd, pid_t pid) { int msg = CHILD_PID; do_write (fd, &msg, sizeof (msg)); do_write (fd, &pid, sizeof (pid)); } static void write_status_and_exit (int fd, int status) { int msg = CHILD_EXITED; do_write (fd, &msg, sizeof (msg)); do_write (fd, &status, sizeof (status)); exit (0); } static void do_exec (int child_err_report_fd, char **argv, char **envp, DBusSpawnChildSetupFunc child_setup, void *user_data) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS int i, max_open; #endif _dbus_verbose_reset (); _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n", _dbus_getpid ()); if (child_setup) (* child_setup) (user_data); #ifdef DBUS_ENABLE_EMBEDDED_TESTS max_open = sysconf (_SC_OPEN_MAX); for (i = 3; i < max_open; i++) { int retval; if (i == child_err_report_fd) continue; retval = fcntl (i, F_GETFD); if (retval != -1 && !(retval & FD_CLOEXEC)) _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i); } #endif if (envp == NULL) { _dbus_assert (environ != NULL); envp = environ; } execve (argv[0], argv, envp); /* Exec failed */ write_err_and_exit (child_err_report_fd, CHILD_EXEC_FAILED); } static void check_babysit_events (pid_t grandchild_pid, int parent_pipe, int revents) { pid_t ret; int status; do { ret = waitpid (grandchild_pid, &status, WNOHANG); /* The man page says EINTR can't happen with WNOHANG, * but there are reports of it (maybe only with valgrind?) */ } while (ret < 0 && errno == EINTR); if (ret == 0) { _dbus_verbose ("no child exited\n"); ; /* no child exited */ } else if (ret < 0) { /* This isn't supposed to happen. */ _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n", _dbus_strerror (errno)); exit (1); } else if (ret == grandchild_pid) { /* Child exited */ _dbus_verbose ("reaped child pid %ld\n", (long) ret); write_status_and_exit (parent_pipe, status); } else { _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n", (int) ret); exit (1); } if (revents & _DBUS_POLLIN) { _dbus_verbose ("babysitter got POLLIN from parent pipe\n"); } if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) { /* Parent is gone, so we just exit */ _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n"); exit (0); } } static int babysit_sigchld_pipe = -1; static void babysit_signal_handler (int signo) { char b = '\0'; again: if (write (babysit_sigchld_pipe, &b, 1) <= 0) if (errno == EINTR) goto again; } static void babysit (pid_t grandchild_pid, int parent_pipe) { int sigchld_pipe[2]; /* We don't exec, so we keep parent state, such as the pid that * _dbus_verbose() uses. Reset the pid here. */ _dbus_verbose_reset (); /* I thought SIGCHLD would just wake up the poll, but * that didn't seem to work, so added this pipe. * Probably the pipe is more likely to work on busted * operating systems anyhow. */ if (pipe (sigchld_pipe) < 0) { _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n"); exit (1); } babysit_sigchld_pipe = sigchld_pipe[WRITE_END]; _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler); write_pid (parent_pipe, grandchild_pid); check_babysit_events (grandchild_pid, parent_pipe, 0); while (TRUE) { DBusPollFD pfds[2]; pfds[0].fd = parent_pipe; pfds[0].events = _DBUS_POLLIN; pfds[0].revents = 0; pfds[1].fd = sigchld_pipe[READ_END]; pfds[1].events = _DBUS_POLLIN; pfds[1].revents = 0; if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR) { _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno)); exit (1); } if (pfds[0].revents != 0) { check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents); } else if (pfds[1].revents & _DBUS_POLLIN) { char b; if (read (sigchld_pipe[READ_END], &b, 1) == -1) { /* ignore */ } /* do waitpid check */ check_babysit_events (grandchild_pid, parent_pipe, 0); } } exit (1); } /** * Spawns a new process. The child_setup * function is passed the given user_data and is run in the child * just before calling exec(). * * Also creates a "babysitter" which tracks the status of the * child process, advising the parent if the child exits. * If the spawn fails, no babysitter is created. * If sitter_p is #NULL, no babysitter is kept. * * @param sitter_p return location for babysitter or #NULL * @param log_name the name under which to log messages about this process being spawned * @param argv the executable and arguments * @param env the environment, or #NULL to copy the parent's * @param child_setup function to call in child pre-exec() * @param user_data user data for setup function * @param error error object to be filled in if function fails * @returns #TRUE on success, #FALSE if error is filled in */ dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, const char *log_name, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT }; pid_t pid; #ifdef HAVE_SYSTEMD int fd_out = -1; int fd_err = -1; #endif _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (argv[0] != NULL); if (sitter_p != NULL) *sitter_p = NULL; sitter = NULL; sitter = _dbus_babysitter_new (); if (sitter == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } sitter->log_name = _dbus_strdup (log_name); if (sitter->log_name == NULL && log_name != NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (sitter->log_name == NULL) sitter->log_name = _dbus_strdup (argv[0]); if (sitter->log_name == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) goto cleanup_and_fail; /* Setting up the babysitter is only useful in the parent, * but we don't want to run out of memory and fail * after we've already forked, since then we'd leak * child processes everywhere. */ sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->error_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd, DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->sitter_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); #ifdef HAVE_SYSTEMD /* This may fail, but it's not critical. * In particular, if we were compiled with journald support but are now * running on a non-systemd system, this is going to fail, so we * have to cope gracefully. */ fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE); fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE); #endif pid = fork (); if (pid < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to fork (%s)", _dbus_strerror (errno)); goto cleanup_and_fail; } else if (pid == 0) { /* Immediate child, this is the babysitter process. */ int grandchild_pid; /* Be sure we crash if the parent exits * and we write to the err_report_pipe */ signal (SIGPIPE, SIG_DFL); /* Close the parent's end of the pipes. */ close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&babysitter_pipe[0].fd); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1].fd, CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { /* Go back to ignoring SIGPIPE, since it's evil */ signal (SIGPIPE, SIG_IGN); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD /* log to systemd journal if possible */ if (fd_out >= 0) dup2 (fd_out, STDOUT_FILENO); if (fd_err >= 0) dup2 (fd_err, STDERR_FILENO); close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif do_exec (child_err_report_pipe[WRITE_END], argv, env, child_setup, user_data); _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); } else { close_and_invalidate (&child_err_report_pipe[WRITE_END]); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif babysit (grandchild_pid, babysitter_pipe[1].fd); _dbus_assert_not_reached ("Got to code after babysit()"); } } else { /* Close the uncared-about ends of the pipes */ close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0].fd = -1; sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; child_err_report_pipe[READ_END] = -1; sitter->sitter_pid = pid; if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); dbus_free_string_array (env); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } cleanup_and_fail: _DBUS_ASSERT_ERROR_IS_SET (error); close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[0].fd); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif if (sitter != NULL) _dbus_babysitter_unref (sitter); return FALSE; } void _dbus_babysitter_set_result_function (DBusBabysitter *sitter, DBusBabysitterFinishedFunc finished, void *user_data) { sitter->finished_cb = finished; sitter->finished_data = user_data; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS static char * get_test_exec (const char *exe, DBusString *scratch_space) { const char *dbus_test_exec; dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC"); if (dbus_test_exec == NULL) dbus_test_exec = DBUS_TEST_EXEC; if (!_dbus_string_init (scratch_space)) return NULL; if (!_dbus_string_append_printf (scratch_space, "%s/%s%s", dbus_test_exec, exe, DBUS_EXEEXT)) { _dbus_string_free (scratch_space); return NULL; } return _dbus_string_get_data (scratch_space); } static void _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) { while (LIVE_CHILDREN (sitter)) babysitter_iteration (sitter, TRUE); } static dbus_bool_t check_spawn_nonexistent (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter = NULL; DBusError error = DBUS_ERROR_INIT; /*** Test launching nonexistent binary */ argv[0] = "/this/does/not/exist/32542sdgafgafdg"; if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching nonexistent executable\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) { _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_segfault (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter = NULL; DBusError error = DBUS_ERROR_INIT; DBusString argv0; /*** Test launching segfault binary */ argv[0] = get_test_exec ("test-segfault", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching segfaulting binary\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) { _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_exit (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter = NULL; DBusError error = DBUS_ERROR_INIT; DBusString argv0; /*** Test launching exit failure binary */ argv[0] = get_test_exec ("test-exit", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) { _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } static dbus_bool_t check_spawn_and_kill (void *data) { char *argv[4] = { NULL, NULL, NULL, NULL }; DBusBabysitter *sitter = NULL; DBusError error = DBUS_ERROR_INIT; DBusString argv0; /*** Test launching sleeping binary then killing it */ argv[0] = get_test_exec ("test-sleep-forever", &argv0); if (argv[0] == NULL) { /* OOM was simulated, never mind */ return TRUE; } if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL, NULL, NULL, &error)) { _dbus_babysitter_kill_child (sitter); _dbus_babysitter_block_for_child_exit (sitter); _dbus_babysitter_set_child_exit_error (sitter, &error); } _dbus_string_free (&argv0); if (sitter) _dbus_babysitter_unref (sitter); if (!dbus_error_is_set (&error)) { _dbus_warn ("Did not get an error after killing spawned binary\n"); return FALSE; } if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) { _dbus_warn ("Not expecting error when killing executable: %s: %s\n", error.name, error.message); dbus_error_free (&error); return FALSE; } dbus_error_free (&error); return TRUE; } dbus_bool_t _dbus_spawn_test (const char *test_data_dir) { if (!_dbus_test_oom_handling ("spawn_nonexistent", check_spawn_nonexistent, NULL)) return FALSE; if (!_dbus_test_oom_handling ("spawn_segfault", check_spawn_segfault, NULL)) return FALSE; if (!_dbus_test_oom_handling ("spawn_exit", check_spawn_exit, NULL)) return FALSE; if (!_dbus_test_oom_handling ("spawn_and_kill", check_spawn_and_kill, NULL)) return FALSE; return TRUE; } #endif dbus-1.10.6/dbus/dbus-userdb-util.c0000644000175000017500000003140612602773110017034 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus * * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #define DBUS_USERDB_INCLUDES_PRIVATE 1 #include "dbus-userdb.h" #include "dbus-test.h" #include "dbus-internals.h" #include "dbus-protocol.h" #include #if HAVE_SYSTEMD #include #endif /** * @addtogroup DBusInternalsUtils * @{ */ /** * Checks to see if the UID sent in is the console user * * @param uid UID of person to check * @param error return location for errors * @returns #TRUE if the UID is the same as the console user and there are no errors */ dbus_bool_t _dbus_is_console_user (dbus_uid_t uid, DBusError *error) { DBusUserDatabase *db; const DBusUserInfo *info; dbus_bool_t result = FALSE; #ifdef HAVE_SYSTEMD /* check if we have logind */ if (access ("/run/systemd/seats/", F_OK) >= 0) { int r; /* Check whether this user is logged in on at least one physical seat */ r = sd_uid_get_seats (uid, 0, NULL); if (r < 0) { dbus_set_error (error, _dbus_error_from_errno (-r), "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s", uid, _dbus_strerror (-r)); return FALSE; } return (r > 0); } #endif #ifdef HAVE_CONSOLE_OWNER_FILE DBusString f; DBusStat st; if (!_dbus_string_init (&f)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE)) { _dbus_string_free(&f); _DBUS_SET_OOM (error); return FALSE; } if (_dbus_stat(&f, &st, NULL) && (st.uid == uid)) { _dbus_string_free(&f); return TRUE; } _dbus_string_free(&f); #endif /* HAVE_CONSOLE_OWNER_FILE */ if (!_dbus_user_database_lock_system ()) { _DBUS_SET_OOM (error); return FALSE; } db = _dbus_user_database_get_system (); if (db == NULL) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database."); _dbus_user_database_unlock_system (); return FALSE; } /* TPTD: this should be cache-safe, we've locked the DB and _dbus_user_at_console doesn't pass it on. */ info = _dbus_user_database_lookup (db, uid, NULL, error); if (info == NULL) { _dbus_user_database_unlock_system (); return FALSE; } result = _dbus_user_at_console (info->username, error); _dbus_user_database_unlock_system (); return result; } /** * Gets user ID given username * * @param username the username * @param uid return location for UID * @returns #TRUE if username existed and we got the UID */ dbus_bool_t _dbus_get_user_id (const DBusString *username, dbus_uid_t *uid) { return _dbus_get_user_id_and_primary_group (username, uid, NULL); } /** * Gets group ID given groupname * * @param groupname the groupname * @param gid return location for GID * @returns #TRUE if group name existed and we got the GID */ dbus_bool_t _dbus_get_group_id (const DBusString *groupname, dbus_gid_t *gid) { DBusUserDatabase *db; const DBusGroupInfo *info; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_groupname (db, groupname, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } *gid = info->gid; _dbus_user_database_unlock_system (); return TRUE; } /** * Gets user ID and primary group given username * * @param username the username * @param uid_p return location for UID * @param gid_p return location for GID * @returns #TRUE if username existed and we got the UID and GID */ dbus_bool_t _dbus_get_user_id_and_primary_group (const DBusString *username, dbus_uid_t *uid_p, dbus_gid_t *gid_p) { DBusUserDatabase *db; const DBusUserInfo *info; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_username (db, username, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } if (uid_p) *uid_p = info->uid; if (gid_p) *gid_p = info->primary_gid; _dbus_user_database_unlock_system (); return TRUE; } /** * Looks up a gid or group name in the user database. Only one of * name or GID can be provided. There are wrapper functions for this * that are better to use, this one does no locking or anything on the * database and otherwise sort of sucks. * * @param db the database * @param gid the group ID or #DBUS_GID_UNSET * @param groupname group name or #NULL * @param error error to fill in * @returns the entry in the database */ DBusGroupInfo* _dbus_user_database_lookup_group (DBusUserDatabase *db, dbus_gid_t gid, const DBusString *groupname, DBusError *error) { DBusGroupInfo *info; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* See if the group is really a number */ if (gid == DBUS_UID_UNSET) { unsigned long n; if (_dbus_is_a_number (groupname, &n)) gid = n; } if (gid != DBUS_GID_UNSET) info = _dbus_hash_table_lookup_uintptr (db->groups, gid); else info = _dbus_hash_table_lookup_string (db->groups_by_name, _dbus_string_get_const_data (groupname)); if (info) { _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", info->gid); return info; } else { if (gid != DBUS_GID_UNSET) _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", gid); else _dbus_verbose ("No cache for groupname \"%s\"\n", _dbus_string_get_const_data (groupname)); info = dbus_new0 (DBusGroupInfo, 1); if (info == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (gid != DBUS_GID_UNSET) { if (!_dbus_group_info_fill_gid (info, gid, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_group_info_free_allocated (info); return NULL; } } else { if (!_dbus_group_info_fill (info, groupname, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_group_info_free_allocated (info); return NULL; } } /* don't use these past here */ gid = DBUS_GID_UNSET; groupname = NULL; if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_group_info_free_allocated (info); return NULL; } if (!_dbus_hash_table_insert_string (db->groups_by_name, info->groupname, info)) { _dbus_hash_table_remove_uintptr (db->groups, info->gid); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } return info; } } /** * Gets the user information for the given group name, * returned group info should not be freed. * * @param db user database * @param groupname the group name * @param info return location for const ref to group info * @param error error location * @returns #FALSE if error is set */ dbus_bool_t _dbus_user_database_get_groupname (DBusUserDatabase *db, const DBusString *groupname, const DBusGroupInfo **info, DBusError *error) { *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); return *info != NULL; } /** * Gets the user information for the given GID, * returned group info should not be freed. * * @param db user database * @param gid the group ID * @param info return location for const ref to group info * @param error error location * @returns #FALSE if error is set */ dbus_bool_t _dbus_user_database_get_gid (DBusUserDatabase *db, dbus_gid_t gid, const DBusGroupInfo **info, DBusError *error) { *info = _dbus_user_database_lookup_group (db, gid, NULL, error); return *info != NULL; } /** * Gets all groups corresponding to the given UID. Returns #FALSE * if no memory, or user isn't known, but always initializes * group_ids to a NULL array. * * @param uid the UID * @param group_ids return location for array of group IDs * @param n_group_ids return location for length of returned array * @returns #TRUE if the UID existed and we got some credentials */ dbus_bool_t _dbus_groups_from_uid (dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids) { DBusUserDatabase *db; const DBusUserInfo *info; *group_ids = NULL; *n_group_ids = 0; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_uid (db, uid, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } _dbus_assert (info->uid == uid); if (info->n_group_ids > 0) { *group_ids = dbus_new (dbus_gid_t, info->n_group_ids); if (*group_ids == NULL) { _dbus_user_database_unlock_system (); return FALSE; } *n_group_ids = info->n_group_ids; memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t)); } _dbus_user_database_unlock_system (); return TRUE; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include /** * Unit test for dbus-userdb.c. * * @returns #TRUE on success. */ dbus_bool_t _dbus_userdb_test (const char *test_data_dir) { const DBusString *username; const DBusString *homedir; dbus_uid_t uid; unsigned long *group_ids; int n_group_ids, i; DBusError error; if (!_dbus_username_from_current_process (&username)) _dbus_assert_not_reached ("didn't get username"); if (!_dbus_homedir_from_current_process (&homedir)) _dbus_assert_not_reached ("didn't get homedir"); if (!_dbus_get_user_id (username, &uid)) _dbus_assert_not_reached ("didn't get uid"); if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids)) _dbus_assert_not_reached ("didn't get groups"); printf (" Current user: %s homedir: %s gids:", _dbus_string_get_const_data (username), _dbus_string_get_const_data (homedir)); for (i=0; i #include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #include "dbus-internals.h" #include "dbus-pipe.h" #include "dbus-protocol.h" #include "dbus-string.h" #define DBUS_USERDB_INCLUDES_PRIVATE 1 #include "dbus-userdb.h" #include "dbus-test.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_RESOURCE_H #include #endif #include #include #include #include #ifdef HAVE_SYSLOG_H #include #endif #ifdef HAVE_SYS_SYSLIMITS_H #include #endif #ifdef HAVE_SYSTEMD #include #endif #ifndef O_BINARY #define O_BINARY 0 #endif /** * @addtogroup DBusInternalsUtils * @{ */ /** * Does the chdir, fork, setsid, etc. to become a daemon process. * * @param pidfile #NULL, or pidfile to create * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none * @param error return location for errors * @param keep_umask #TRUE to keep the original umask * @returns #FALSE on failure */ dbus_bool_t _dbus_become_daemon (const DBusString *pidfile, DBusPipe *print_pid_pipe, DBusError *error, dbus_bool_t keep_umask) { const char *s; pid_t child_pid; int dev_null_fd; _dbus_verbose ("Becoming a daemon...\n"); _dbus_verbose ("chdir to /\n"); if (chdir ("/") < 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not chdir() to root directory"); return FALSE; } _dbus_verbose ("forking...\n"); switch ((child_pid = fork ())) { case -1: _dbus_verbose ("fork failed\n"); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to fork daemon: %s", _dbus_strerror (errno)); return FALSE; break; case 0: _dbus_verbose ("in child, closing std file descriptors\n"); /* silently ignore failures here, if someone * doesn't have /dev/null we may as well try * to continue anyhow */ dev_null_fd = open ("/dev/null", O_RDWR); if (dev_null_fd >= 0) { dup2 (dev_null_fd, 0); dup2 (dev_null_fd, 1); s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); if (s == NULL || *s == '\0') dup2 (dev_null_fd, 2); else _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); close (dev_null_fd); } if (!keep_umask) { /* Get a predictable umask */ _dbus_verbose ("setting umask\n"); umask (022); } _dbus_verbose ("calling setsid()\n"); if (setsid () == -1) _dbus_assert_not_reached ("setsid() failed"); break; default: if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe, child_pid, error)) { _dbus_verbose ("pid file or pipe write failed: %s\n", error->message); kill (child_pid, SIGTERM); return FALSE; } _dbus_verbose ("parent exiting\n"); _exit (0); break; } return TRUE; } /** * Creates a file containing the process ID. * * @param filename the filename to write to * @param pid our process ID * @param error return location for errors * @returns #FALSE on failure */ static dbus_bool_t _dbus_write_pid_file (const DBusString *filename, unsigned long pid, DBusError *error) { const char *cfilename; int fd; FILE *f; cfilename = _dbus_string_get_const_data (filename); fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); if (fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open \"%s\": %s", cfilename, _dbus_strerror (errno)); return FALSE; } if ((f = fdopen (fd, "w")) == NULL) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); _dbus_close (fd, NULL); return FALSE; } if (fprintf (f, "%lu\n", pid) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to write to \"%s\": %s", cfilename, _dbus_strerror (errno)); fclose (f); return FALSE; } if (fclose (f) == EOF) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to close \"%s\": %s", cfilename, _dbus_strerror (errno)); return FALSE; } return TRUE; } /** * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both * NULL. * * @param pidfile the file to write to or #NULL * @param print_pid_pipe the pipe to write to or #NULL * @param pid_to_write the pid to write out * @param error error on failure * @returns FALSE if error is set */ dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, DBusPipe *print_pid_pipe, dbus_pid_t pid_to_write, DBusError *error) { if (pidfile) { _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile)); if (!_dbus_write_pid_file (pidfile, pid_to_write, error)) { _dbus_verbose ("pid file write failed\n"); _DBUS_ASSERT_ERROR_IS_SET(error); return FALSE; } } else { _dbus_verbose ("No pid file requested\n"); } if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe)) { DBusString pid; int bytes; _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd); if (!_dbus_string_init (&pid)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append_int (&pid, pid_to_write) || !_dbus_string_append (&pid, "\n")) { _dbus_string_free (&pid); _DBUS_SET_OOM (error); return FALSE; } bytes = _dbus_string_get_length (&pid); if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes) { /* _dbus_pipe_write sets error only on failure, not short write */ if (error != NULL && !dbus_error_is_set(error)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Printing message bus PID: did not write enough bytes\n"); } _dbus_string_free (&pid); return FALSE; } _dbus_string_free (&pid); } else { _dbus_verbose ("No pid pipe to write to\n"); } return TRUE; } /** * Verify that after the fork we can successfully change to this user. * * @param user the username given in the daemon configuration * @returns #TRUE if username is valid */ dbus_bool_t _dbus_verify_daemon_user (const char *user) { DBusString u; _dbus_string_init_const (&u, user); return _dbus_get_user_id_and_primary_group (&u, NULL, NULL); } /* The HAVE_LIBAUDIT case lives in selinux.c */ #ifndef HAVE_LIBAUDIT /** * Changes the user and group the bus is running as. * * @param user the user to become * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error) { dbus_uid_t uid; dbus_gid_t gid; DBusString u; _dbus_string_init_const (&u, user); if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) { dbus_set_error (error, DBUS_ERROR_FAILED, "User '%s' does not appear to exist?", user); return FALSE; } /* setgroups() only works if we are a privileged process, * so we don't return error on failure; the only possible * failure is that we don't have perms to do it. * * not sure this is right, maybe if setuid() * is going to work then setgroups() should also work. */ if (setgroups (0, NULL) < 0) _dbus_warn ("Failed to drop supplementary groups: %s\n", _dbus_strerror (errno)); /* Set GID first, or the setuid may remove our permission * to change the GID */ if (setgid (gid) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set GID to %lu: %s", gid, _dbus_strerror (errno)); return FALSE; } if (setuid (uid) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set UID to %lu: %s", uid, _dbus_strerror (errno)); return FALSE; } return TRUE; } #endif /* !HAVE_LIBAUDIT */ #ifdef HAVE_SETRLIMIT /* We assume that if we have setrlimit, we also have getrlimit and * struct rlimit. */ struct DBusRLimit { struct rlimit lim; }; DBusRLimit * _dbus_rlimit_save_fd_limit (DBusError *error) { DBusRLimit *self; self = dbus_new0 (DBusRLimit, 1); if (self == NULL) { _DBUS_SET_OOM (error); return NULL; } if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to get fd limit: %s", _dbus_strerror (errno)); dbus_free (self); return NULL; } return self; } dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, DBusError *error) { struct rlimit lim; /* No point to doing this practically speaking * if we're not uid 0. We expect the system * bus to use this before we change UID, and * the session bus takes the Linux default, * currently 1024 for cur and 4096 for max. */ if (getuid () != 0) { /* not an error, we're probably the session bus */ return TRUE; } if (getrlimit (RLIMIT_NOFILE, &lim) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to get fd limit: %s", _dbus_strerror (errno)); return FALSE; } if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired) { /* not an error, everything is fine */ return TRUE; } /* Ignore "maximum limit", assume we have the "superuser" * privileges. On Linux this is CAP_SYS_RESOURCE. */ lim.rlim_cur = lim.rlim_max = desired; if (setrlimit (RLIMIT_NOFILE, &lim) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set fd limit to %u: %s", desired, _dbus_strerror (errno)); return FALSE; } return TRUE; } dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, DBusError *error) { if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to restore old fd limit: %s", _dbus_strerror (errno)); return FALSE; } return TRUE; } #else /* !HAVE_SETRLIMIT */ static void fd_limit_not_supported (DBusError *error) { dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "cannot change fd limit on this platform"); } DBusRLimit * _dbus_rlimit_save_fd_limit (DBusError *error) { fd_limit_not_supported (error); return NULL; } dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, DBusError *error) { fd_limit_not_supported (error); return FALSE; } dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, DBusError *error) { fd_limit_not_supported (error); return FALSE; } #endif void _dbus_rlimit_free (DBusRLimit *lim) { dbus_free (lim); } void _dbus_init_system_log (dbus_bool_t is_daemon) { #ifdef HAVE_SYSLOG_H int logopts = LOG_PID; #if HAVE_DECL_LOG_PERROR #ifdef HAVE_SYSTEMD if (!is_daemon || sd_booted () <= 0) #endif logopts |= LOG_PERROR; #endif openlog ("dbus", logopts, LOG_DAEMON); #endif } /** * Log a message to the system log file (e.g. syslog on Unix). * * @param severity a severity value * @param msg a printf-style format string */ void _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) { va_list args; va_start (args, msg); _dbus_system_logv (severity, msg, args); va_end (args); } /** * Log a message to the system log file (e.g. syslog on Unix). * * @param severity a severity value * @param msg a printf-style format string * @param args arguments for the format string * * If the FATAL severity is given, this function will terminate the program * with an error code. */ void _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args) { va_list tmp; #ifdef HAVE_SYSLOG_H int flags; switch (severity) { case DBUS_SYSTEM_LOG_INFO: flags = LOG_DAEMON | LOG_NOTICE; break; case DBUS_SYSTEM_LOG_WARNING: flags = LOG_DAEMON | LOG_WARNING; break; case DBUS_SYSTEM_LOG_SECURITY: flags = LOG_AUTH | LOG_NOTICE; break; case DBUS_SYSTEM_LOG_FATAL: flags = LOG_DAEMON|LOG_CRIT; break; default: return; } DBUS_VA_COPY (tmp, args); vsyslog (flags, msg, tmp); va_end (tmp); #endif #if !defined(HAVE_SYSLOG_H) || !HAVE_DECL_LOG_PERROR { /* vsyslog() won't write to stderr, so we'd better do it */ DBUS_VA_COPY (tmp, args); fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ()); vfprintf (stderr, msg, tmp); fputc ('\n', stderr); va_end (tmp); } #endif if (severity == DBUS_SYSTEM_LOG_FATAL) exit (1); } /** Installs a UNIX signal handler * * @param sig the signal to handle * @param handler the handler */ void _dbus_set_signal_handler (int sig, DBusSignalHandler handler) { struct sigaction act; sigset_t empty_mask; sigemptyset (&empty_mask); act.sa_handler = handler; act.sa_mask = empty_mask; act.sa_flags = 0; sigaction (sig, &act, NULL); } /** Checks if a file exists * * @param file full path to the file * @returns #TRUE if file exists */ dbus_bool_t _dbus_file_exists (const char *file) { return (access (file, F_OK) == 0); } /** Checks if user is at the console * * @param username user to check * @param error return location for errors * @returns #TRUE is the user is at the consolei and there are no errors */ dbus_bool_t _dbus_user_at_console (const char *username, DBusError *error) { DBusString u, f; dbus_bool_t result; result = FALSE; if (!_dbus_string_init (&f)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR)) { _DBUS_SET_OOM (error); goto out; } _dbus_string_init_const (&u, username); if (!_dbus_concat_dir_and_file (&f, &u)) { _DBUS_SET_OOM (error); goto out; } result = _dbus_file_exists (_dbus_string_get_const_data (&f)); out: _dbus_string_free (&f); return result; } /** * Checks whether the filename is an absolute path * * @param filename the filename * @returns #TRUE if an absolute path */ dbus_bool_t _dbus_path_is_absolute (const DBusString *filename) { if (_dbus_string_get_length (filename) > 0) return _dbus_string_get_byte (filename, 0) == '/'; else return FALSE; } /** * stat() wrapper. * * @param filename the filename to stat * @param statbuf the stat info to fill in * @param error return location for error * @returns #FALSE if error was set */ dbus_bool_t _dbus_stat (const DBusString *filename, DBusStat *statbuf, DBusError *error) { const char *filename_c; struct stat sb; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (stat (filename_c, &sb) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "%s", _dbus_strerror (errno)); return FALSE; } statbuf->mode = sb.st_mode; statbuf->nlink = sb.st_nlink; statbuf->uid = sb.st_uid; statbuf->gid = sb.st_gid; statbuf->size = sb.st_size; statbuf->atime = sb.st_atime; statbuf->mtime = sb.st_mtime; statbuf->ctime = sb.st_ctime; return TRUE; } /** * Internals of directory iterator */ struct DBusDirIter { DIR *d; /**< The DIR* from opendir() */ }; /** * Open a directory to iterate over. * * @param filename the directory name * @param error exception return object or #NULL * @returns new iterator, or #NULL on error */ DBusDirIter* _dbus_directory_open (const DBusString *filename, DBusError *error) { DIR *d; DBusDirIter *iter; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); d = opendir (filename_c); if (d == NULL) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to read directory \"%s\": %s", filename_c, _dbus_strerror (errno)); return NULL; } iter = dbus_new0 (DBusDirIter, 1); if (iter == NULL) { closedir (d); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Could not allocate memory for directory iterator"); return NULL; } iter->d = d; return iter; } /** * Get next file in the directory. Will not return "." or ".." on * UNIX. If an error occurs, the contents of "filename" are * undefined. The error is never set if the function succeeds. * * This function is not re-entrant, and not necessarily thread-safe. * Only use it for test code or single-threaded utilities. * * @param iter the iterator * @param filename string to be set to the next file in the dir * @param error return location for error * @returns #TRUE if filename was filled in with a new filename */ dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, DBusError *error) { struct dirent *ent; int err; _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: errno = 0; ent = readdir (iter->d); if (!ent) { err = errno; if (err != 0) dbus_set_error (error, _dbus_error_from_errno (err), "%s", _dbus_strerror (err)); return FALSE; } else if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) goto again; else { _dbus_string_set_length (filename, 0); if (!_dbus_string_append (filename, ent->d_name)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "No memory to read directory entry"); return FALSE; } else { return TRUE; } } } /** * Closes a directory iteration. */ void _dbus_directory_close (DBusDirIter *iter) { closedir (iter->d); dbus_free (iter); } static dbus_bool_t fill_user_info_from_group (struct group *g, DBusGroupInfo *info, DBusError *error) { _dbus_assert (g->gr_name != NULL); info->gid = g->gr_gid; info->groupname = _dbus_strdup (g->gr_name); /* info->members = dbus_strdupv (g->gr_mem) */ if (info->groupname == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } return TRUE; } static dbus_bool_t fill_group_info (DBusGroupInfo *info, dbus_gid_t gid, const DBusString *groupname, DBusError *error) { const char *group_c_str; _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); if (groupname) group_c_str = _dbus_string_get_const_data (groupname); else group_c_str = NULL; /* For now assuming that the getgrnam() and getgrgid() flavors * always correspond to the pwnam flavors, if not we have * to add more configure checks. */ #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) { struct group *g; int result; size_t buflen; char *buf; struct group g_str; dbus_bool_t b; /* retrieve maximum needed size for buf */ buflen = sysconf (_SC_GETGR_R_SIZE_MAX); /* sysconf actually returns a long, but everything else expects size_t, * so just recast here. * https://bugs.freedesktop.org/show_bug.cgi?id=17061 */ if ((long) buflen <= 0) buflen = 1024; result = -1; while (1) { buf = dbus_malloc (buflen); if (buf == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } g = NULL; #ifdef HAVE_POSIX_GETPWNAM_R if (group_c_str) result = getgrnam_r (group_c_str, &g_str, buf, buflen, &g); else result = getgrgid_r (gid, &g_str, buf, buflen, &g); #else g = getgrnam_r (group_c_str, &g_str, buf, buflen); result = 0; #endif /* !HAVE_POSIX_GETPWNAM_R */ /* Try a bigger buffer if ERANGE was returned: https://bugs.freedesktop.org/show_bug.cgi?id=16727 */ if (result == ERANGE && buflen < 512 * 1024) { dbus_free (buf); buflen *= 2; } else { break; } } if (result == 0 && g == &g_str) { b = fill_user_info_from_group (g, info, error); dbus_free (buf); return b; } else { dbus_set_error (error, _dbus_error_from_errno (errno), "Group %s unknown or failed to look it up\n", group_c_str ? group_c_str : "???"); dbus_free (buf); return FALSE; } } #else /* ! HAVE_GETPWNAM_R */ { /* I guess we're screwed on thread safety here */ struct group *g; g = getgrnam (group_c_str); if (g != NULL) { return fill_user_info_from_group (g, info, error); } else { dbus_set_error (error, _dbus_error_from_errno (errno), "Group %s unknown or failed to look it up\n", group_c_str ? group_c_str : "???"); return FALSE; } } #endif /* ! HAVE_GETPWNAM_R */ } /** * Initializes the given DBusGroupInfo struct * with information about the given group name. * * @param info the group info struct * @param groupname name of group * @param error the error return * @returns #FALSE if error is set */ dbus_bool_t _dbus_group_info_fill (DBusGroupInfo *info, const DBusString *groupname, DBusError *error) { return fill_group_info (info, DBUS_GID_UNSET, groupname, error); } /** * Initializes the given DBusGroupInfo struct * with information about the given group ID. * * @param info the group info struct * @param gid group ID * @param error the error return * @returns #FALSE if error is set */ dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info, dbus_gid_t gid, DBusError *error) { return fill_group_info (info, gid, NULL, error); } /** * Parse a UNIX user from the bus config file. On Windows, this should * simply always fail (just return #FALSE). * * @param username the username text * @param uid_p place to return the uid * @returns #TRUE on success */ dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username, dbus_uid_t *uid_p) { return _dbus_get_user_id (username, uid_p); } /** * Parse a UNIX group from the bus config file. On Windows, this should * simply always fail (just return #FALSE). * * @param groupname the groupname text * @param gid_p place to return the gid * @returns #TRUE on success */ dbus_bool_t _dbus_parse_unix_group_from_config (const DBusString *groupname, dbus_gid_t *gid_p) { return _dbus_get_group_id (groupname, gid_p); } /** * Gets all groups corresponding to the given UNIX user ID. On UNIX, * just calls _dbus_groups_from_uid(). On Windows, should always * fail since we don't know any UNIX groups. * * @param uid the UID * @param group_ids return location for array of group IDs * @param n_group_ids return location for length of returned array * @returns #TRUE if the UID existed and we got some credentials */ dbus_bool_t _dbus_unix_groups_from_uid (dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids) { return _dbus_groups_from_uid (uid, group_ids, n_group_ids); } /** * Checks to see if the UNIX user ID is at the console. * Should always fail on Windows (set the error to * #DBUS_ERROR_NOT_SUPPORTED). * * @param uid UID of person to check * @param error return location for errors * @returns #TRUE if the UID is the same as the console user and there are no errors */ dbus_bool_t _dbus_unix_user_is_at_console (dbus_uid_t uid, DBusError *error) { return _dbus_is_console_user (uid, error); } /** * Checks to see if the UNIX user ID matches the UID of * the process. Should always return #FALSE on Windows. * * @param uid the UNIX user ID * @returns #TRUE if this uid owns the process. */ dbus_bool_t _dbus_unix_user_is_process_owner (dbus_uid_t uid) { return uid == _dbus_geteuid (); } /** * Checks to see if the Windows user SID matches the owner of * the process. Should always return #FALSE on UNIX. * * @param windows_sid the Windows user SID * @returns #TRUE if this user owns the process. */ dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid) { return FALSE; } /** @} */ /* End of DBusInternalsUtils functions */ /** * @addtogroup DBusString * * @{ */ /** * Get the directory name from a complete filename * @param filename the filename * @param dirname string to append directory name to * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_get_dirname (const DBusString *filename, DBusString *dirname) { int sep; _dbus_assert (filename != dirname); _dbus_assert (filename != NULL); _dbus_assert (dirname != NULL); /* Ignore any separators on the end */ sep = _dbus_string_get_length (filename); if (sep == 0) return _dbus_string_append (dirname, "."); /* empty string passed in */ while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') --sep; _dbus_assert (sep >= 0); if (sep == 0) return _dbus_string_append (dirname, "/"); /* Now find the previous separator */ _dbus_string_find_byte_backward (filename, sep, '/', &sep); if (sep < 0) return _dbus_string_append (dirname, "."); /* skip multiple separators */ while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') --sep; _dbus_assert (sep >= 0); if (sep == 0 && _dbus_string_get_byte (filename, 0) == '/') return _dbus_string_append (dirname, "/"); else return _dbus_string_copy_len (filename, 0, sep - 0, dirname, _dbus_string_get_length (dirname)); } /** @} */ /* DBusString stuff */ static void string_squash_nonprintable (DBusString *str) { unsigned char *buf; int i, len; buf = _dbus_string_get_data (str); len = _dbus_string_get_length (str); for (i = 0; i < len; i++) { unsigned char c = (unsigned char) buf[i]; if (c == '\0') buf[i] = ' '; else if (c < 0x20 || c > 127) buf[i] = '?'; } } /** * Get a printable string describing the command used to execute * the process with pid. This string should only be used for * informative purposes such as logging; it may not be trusted. * * The command is guaranteed to be printable ASCII and no longer * than max_len. * * @param pid Process id * @param str Append command to this string * @param max_len Maximum length of returned command * @param error return location for errors * @returns #FALSE on error */ dbus_bool_t _dbus_command_for_pid (unsigned long pid, DBusString *str, int max_len, DBusError *error) { /* This is all Linux-specific for now */ DBusString path; DBusString cmdline; int fd; if (!_dbus_string_init (&path)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_init (&cmdline)) { _DBUS_SET_OOM (error); _dbus_string_free (&path); return FALSE; } if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid)) goto oom; fd = open (_dbus_string_get_const_data (&path), O_RDONLY); if (fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open \"%s\": %s", _dbus_string_get_const_data (&path), _dbus_strerror (errno)); goto fail; } if (!_dbus_read (fd, &cmdline, max_len)) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to read from \"%s\": %s", _dbus_string_get_const_data (&path), _dbus_strerror (errno)); _dbus_close (fd, NULL); goto fail; } if (!_dbus_close (fd, error)) goto fail; string_squash_nonprintable (&cmdline); if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str))) goto oom; _dbus_string_free (&cmdline); _dbus_string_free (&path); return TRUE; oom: _DBUS_SET_OOM (error); fail: _dbus_string_free (&cmdline); _dbus_string_free (&path); return FALSE; } /* * replaces the term DBUS_PREFIX in configure_time_path by the * current dbus installation directory. On unix this function is a noop * * @param configure_time_path * @return real path */ const char * _dbus_replace_install_prefix (const char *configure_time_path) { return configure_time_path; } #define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" #define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services" /** * Returns the standard directories for a session bus to look for service * activation files * * On UNIX this should be the standard xdg freedesktop.org data directories: * * XDG_DATA_HOME=${XDG_DATA_HOME-$HOME/.local/share} * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} * * and * * DBUS_DATADIR * * @param dirs the directory list we are returning * @returns #FALSE on OOM */ dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs) { const char *xdg_data_home; const char *xdg_data_dirs; DBusString servicedir_path; if (!_dbus_string_init (&servicedir_path)) return FALSE; xdg_data_home = _dbus_getenv ("XDG_DATA_HOME"); xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS"); if (xdg_data_home != NULL) { if (!_dbus_string_append (&servicedir_path, xdg_data_home)) goto oom; } else { const DBusString *homedir; DBusString local_share; if (!_dbus_homedir_from_current_process (&homedir)) goto oom; if (!_dbus_string_append (&servicedir_path, _dbus_string_get_const_data (homedir))) goto oom; _dbus_string_init_const (&local_share, "/.local/share"); if (!_dbus_concat_dir_and_file (&servicedir_path, &local_share)) goto oom; } if (!_dbus_string_append (&servicedir_path, ":")) goto oom; if (xdg_data_dirs != NULL) { if (!_dbus_string_append (&servicedir_path, xdg_data_dirs)) goto oom; if (!_dbus_string_append (&servicedir_path, ":")) goto oom; } else { if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:")) goto oom; } /* * add configured datadir to defaults * this may be the same as an xdg dir * however the config parser should take * care of duplicates */ if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR)) goto oom; if (!_dbus_split_paths_and_append (&servicedir_path, DBUS_UNIX_STANDARD_SESSION_SERVICEDIR, dirs)) goto oom; _dbus_string_free (&servicedir_path); return TRUE; oom: _dbus_string_free (&servicedir_path); return FALSE; } /** * Returns the standard directories for a system bus to look for service * activation files * * On UNIX this should be the standard xdg freedesktop.org data directories: * * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} * * and * * DBUS_DATADIR * * On Windows there is no system bus and this function can return nothing. * * @param dirs the directory list we are returning * @returns #FALSE on OOM */ dbus_bool_t _dbus_get_standard_system_servicedirs (DBusList **dirs) { /* * DBUS_DATADIR may be the same as one of the standard directories. However, * the config parser should take care of the duplicates. * * Also, append /lib as counterpart of /usr/share on the root * directory (the root directory does not know /share), in order to * facilitate early boot system bus activation where /usr might not * be available. */ static const char standard_search_path[] = "/usr/local/share:" "/usr/share:" DBUS_DATADIR ":" "/lib"; DBusString servicedir_path; _dbus_string_init_const (&servicedir_path, standard_search_path); return _dbus_split_paths_and_append (&servicedir_path, DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR, dirs); } /** * Append the absolute path of the system.conf file * (there is no system bus on Windows so this can just * return FALSE and print a warning or something) * * @param str the string to append to * @returns #FALSE if no memory */ dbus_bool_t _dbus_append_system_config_file (DBusString *str) { return _dbus_string_append (str, DBUS_SYSTEM_CONFIG_FILE); } /** * Append the absolute path of the session.conf file. * * @param str the string to append to * @returns #FALSE if no memory */ dbus_bool_t _dbus_append_session_config_file (DBusString *str) { return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE); } dbus-1.10.6/dbus/dbus-shell.h0000644000175000017500000000252512602773110015711 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-shell.h Shell command line utility functions. * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SHELL_H #define DBUS_SHELL_H DBUS_BEGIN_DECLS char* _dbus_shell_unquote (const char *quoted_string); dbus_bool_t _dbus_shell_parse_argv (const char *command_line, int *argcp, char ***argvp, DBusError *error); DBUS_END_DECLS #endif /* DBUS_SHELL_H */ dbus-1.10.6/dbus/dbus-shell.c0000644000175000017500000004221312602773110015702 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-shell.c Shell command line utility functions. * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "dbus-internals.h" #include "dbus-list.h" #include "dbus-memory.h" #include "dbus-protocol.h" #include "dbus-shell.h" #include "dbus-string.h" /* Single quotes preserve the literal string exactly. escape * sequences are not allowed; not even \' - if you want a ' * in the quoted text, you have to do something like 'foo'\''bar' * * Double quotes allow $ ` " \ and newline to be escaped with backslash. * Otherwise double quotes preserve things literally. */ static dbus_bool_t unquote_string_inplace (char* str, char** end) { char* dest; char* s; char quote_char; dest = s = str; quote_char = *s; if (!(*s == '"' || *s == '\'')) { *end = str; return FALSE; } /* Skip the initial quote mark */ ++s; if (quote_char == '"') { while (*s) { _dbus_assert(s > dest); /* loop invariant */ switch (*s) { case '"': /* End of the string, return now */ *dest = '\0'; ++s; *end = s; return TRUE; case '\\': /* Possible escaped quote or \ */ ++s; switch (*s) { case '"': case '\\': case '`': case '$': case '\n': *dest = *s; ++s; ++dest; break; default: /* not an escaped char */ *dest = '\\'; ++dest; /* ++s already done. */ break; } break; default: *dest = *s; ++dest; ++s; break; } _dbus_assert(s > dest); /* loop invariant */ } } else { while (*s) { _dbus_assert(s > dest); /* loop invariant */ if (*s == '\'') { /* End of the string, return now */ *dest = '\0'; ++s; *end = s; return TRUE; } else { *dest = *s; ++dest; ++s; } _dbus_assert(s > dest); /* loop invariant */ } } /* If we reach here this means the close quote was never encountered */ *dest = '\0'; *end = s; return FALSE; } /** * Unquotes a string as the shell (/bin/sh) would. Only handles * quotes; if a string contains file globs, arithmetic operators, * variables, backticks, redirections, or other special-to-the-shell * features, the result will be different from the result a real shell * would produce (the variables, backticks, etc. will be passed * through literally instead of being expanded). This function is * guaranteed to succeed if applied to the result of * _dbus_shell_quote(). If it fails, it returns %NULL. * The @p quoted_string need not actually contain quoted or * escaped text; _dbus_shell_unquote() simply goes through the string and * unquotes/unescapes anything that the shell would. Both single and * double quotes are handled, as are escapes including escaped * newlines. The return value must be freed with dbus_free(). * * Shell quoting rules are a bit strange. Single quotes preserve the * literal string exactly. escape sequences are not allowed; not even * \' - if you want a ' in the quoted text, you have to do something * like 'foo'\''bar'. Double quotes allow $, `, ", \, and newline to * be escaped with backslash. Otherwise double quotes preserve things * literally. * * @param quoted_string shell-quoted string **/ char* _dbus_shell_unquote (const char *quoted_string) { char *unquoted; char *end; char *start; char *ret; DBusString retval; unquoted = _dbus_strdup (quoted_string); if (unquoted == NULL) return NULL; start = unquoted; end = unquoted; if (!_dbus_string_init (&retval)) { dbus_free (unquoted); return NULL; } /* The loop allows cases such as * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo' */ while (*start) { /* Append all non-quoted chars, honoring backslash escape */ while (*start && !(*start == '"' || *start == '\'')) { if (*start == '\\') { /* all characters can get escaped by backslash, * except newline, which is removed if it follows * a backslash outside of quotes */ ++start; if (*start) { if (*start != '\n') { if (!_dbus_string_append_byte (&retval, *start)) goto error; } ++start; } } else { if (!_dbus_string_append_byte (&retval, *start)) goto error; ++start; } } if (*start) { if (!unquote_string_inplace (start, &end)) goto error; else { if (!_dbus_string_append (&retval, start)) goto error; start = end; } } } ret = _dbus_strdup (_dbus_string_get_data (&retval)); if (!ret) goto error; dbus_free (unquoted); _dbus_string_free (&retval); return ret; error: dbus_free (unquoted); _dbus_string_free (&retval); return NULL; } /* _dbus_shell_parse_argv() does a semi-arbitrary weird subset of the way * the shell parses a command line. We don't do variable expansion, * don't understand that operators are tokens, don't do tilde expansion, * don't do command substitution, no arithmetic expansion, IFS gets ignored, * don't do filename globs, don't remove redirection stuff, etc. * * READ THE UNIX98 SPEC on "Shell Command Language" before changing * the behavior of this code. * * Steps to parsing the argv string: * * - tokenize the string (but since we ignore operators, * our tokenization may diverge from what the shell would do) * note that tokenization ignores the internals of a quoted * word and it always splits on spaces, not on IFS even * if we used IFS. We also ignore "end of input indicator" * (I guess this is control-D?) * * Tokenization steps, from UNIX98 with operator stuff removed, * are: * * 1) "If the current character is backslash, single-quote or * double-quote (\, ' or ") and it is not quoted, it will affect * quoting for subsequent characters up to the end of the quoted * text. The rules for quoting are as described in Quoting * . During token recognition no substitutions will be actually * performed, and the result token will contain exactly the * characters that appear in the input (except for newline * character joining), unmodified, including any embedded or * enclosing quotes or substitution operators, between the quote * mark and the end of the quoted text. The token will not be * delimited by the end of the quoted field." * * 2) "If the current character is an unquoted newline character, * the current token will be delimited." * * 3) "If the current character is an unquoted blank character, any * token containing the previous character is delimited and the * current character will be discarded." * * 4) "If the previous character was part of a word, the current * character will be appended to that word." * * 5) "If the current character is a "#", it and all subsequent * characters up to, but excluding, the next newline character * will be discarded as a comment. The newline character that * ends the line is not considered part of the comment. The * "#" starts a comment only when it is at the beginning of a * token. Since the search for the end-of-comment does not * consider an escaped newline character specially, a comment * cannot be continued to the next line." * * 6) "The current character will be used as the start of a new word." * * * - for each token (word), perform portions of word expansion, namely * field splitting (using default whitespace IFS) and quote * removal. Field splitting may increase the number of words. * Quote removal does not increase the number of words. * * "If the complete expansion appropriate for a word results in an * empty field, that empty field will be deleted from the list of * fields that form the completely expanded command, unless the * original word contained single-quote or double-quote characters." * - UNIX98 spec * * */ static dbus_bool_t delimit_token (DBusString *token, DBusList **retval, DBusError *error) { char *str; str = _dbus_strdup (_dbus_string_get_data (token)); if (!str) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_list_append (retval, str)) { dbus_free (str); _DBUS_SET_OOM (error); return FALSE; } return TRUE; } static DBusList* tokenize_command_line (const char *command_line, DBusError *error) { char current_quote; const char *p; DBusString current_token; DBusList *retval = NULL; dbus_bool_t quoted;; current_quote = '\0'; quoted = FALSE; p = command_line; if (!_dbus_string_init (¤t_token)) { _DBUS_SET_OOM (error); return NULL; } while (*p) { if (current_quote == '\\') { if (*p == '\n') { /* we append nothing; backslash-newline become nothing */ } else { if (!_dbus_string_append_byte (¤t_token, '\\') || !_dbus_string_append_byte (¤t_token, *p)) { _DBUS_SET_OOM (error); goto error; } } current_quote = '\0'; } else if (current_quote == '#') { /* Discard up to and including next newline */ while (*p && *p != '\n') ++p; current_quote = '\0'; if (*p == '\0') break; } else if (current_quote) { if (*p == current_quote && /* check that it isn't an escaped double quote */ !(current_quote == '"' && quoted)) { /* close the quote */ current_quote = '\0'; } /* Everything inside quotes, and the close quote, * gets appended literally. */ if (!_dbus_string_append_byte (¤t_token, *p)) { _DBUS_SET_OOM (error); goto error; } } else { switch (*p) { case '\n': if (!delimit_token (¤t_token, &retval, error)) goto error; _dbus_string_free (¤t_token); if (!_dbus_string_init (¤t_token)) { _DBUS_SET_OOM (error); goto init_error; } break; case ' ': case '\t': /* If the current token contains the previous char, delimit * the current token. A nonzero length * token should always contain the previous char. */ if (_dbus_string_get_length (¤t_token) > 0) { if (!delimit_token (¤t_token, &retval, error)) goto error; _dbus_string_free (¤t_token); if (!_dbus_string_init (¤t_token)) { _DBUS_SET_OOM (error); goto init_error; } } /* discard all unquoted blanks (don't add them to a token) */ break; /* single/double quotes are appended to the token, * escapes are maybe appended next time through the loop, * comment chars are never appended. */ case '\'': case '"': if (!_dbus_string_append_byte (¤t_token, *p)) { _DBUS_SET_OOM (error); goto error; } /* FALL THRU */ case '#': case '\\': current_quote = *p; break; default: /* Combines rules 4) and 6) - if we have a token, append to it, * otherwise create a new token. */ if (!_dbus_string_append_byte (¤t_token, *p)) { _DBUS_SET_OOM (error); goto error; } break; } } /* We need to count consecutive backslashes mod 2, * to detect escaped doublequotes. */ if (*p != '\\') quoted = FALSE; else quoted = !quoted; ++p; } if (!delimit_token (¤t_token, &retval, error)) goto error; if (current_quote) { dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "Unclosed quotes in command line"); goto error; } if (retval == NULL) { dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "No tokens found in command line"); goto error; } _dbus_string_free (¤t_token); return retval; error: _dbus_string_free (¤t_token); init_error: if (retval) { _dbus_list_foreach (&retval, (DBusForeachFunction) dbus_free, NULL); _dbus_list_clear (&retval); } return NULL; } /** * _dbus_shell_parse_argv: * * Parses a command line into an argument vector, in much the same way * the shell would, but without many of the expansions the shell would * perform (variable expansion, globs, operators, filename expansion, * etc. are not supported). The results are defined to be the same as * those you would get from a UNIX98 /bin/sh, as long as the input * contains none of the unsupported shell expansions. If the input * does contain such expansions, they are passed through * literally. Free the returned vector with dbus_free_string_array(). * * @param command_line command line to parse * @param argcp return location for number of args * @param argvp return location for array of args * @param error error information **/ dbus_bool_t _dbus_shell_parse_argv (const char *command_line, int *argcp, char ***argvp, DBusError *error) { /* Code based on poptParseArgvString() from libpopt */ int argc = 0; char **argv = NULL; DBusList *tokens = NULL; int i; DBusList *tmp_list; if (!command_line) { _dbus_verbose ("Command line is NULL\n"); return FALSE; } tokens = tokenize_command_line (command_line, error); if (tokens == NULL) { _dbus_verbose ("No tokens for command line '%s'\n", command_line); return FALSE; } /* Because we can't have introduced any new blank space into the * tokens (we didn't do any new expansions), we don't need to * perform field splitting. If we were going to honor IFS or do any * expansions, we would have to do field splitting on each word * here. Also, if we were going to do any expansion we would need to * remove any zero-length words that didn't contain quotes * originally; but since there's no expansion we know all words have * nonzero length, unless they contain quotes. * * So, we simply remove quotes, and don't do any field splitting or * empty word removal, since we know there was no way to introduce * such things. */ argc = _dbus_list_get_length (&tokens); argv = dbus_new (char *, argc + 1); if (!argv) { _DBUS_SET_OOM (error); goto error; } i = 0; tmp_list = tokens; while (tmp_list) { argv[i] = _dbus_shell_unquote (tmp_list->data); if (!argv[i]) { int j; for (j = 0; j < i; j++) dbus_free(argv[j]); dbus_free (argv); _DBUS_SET_OOM (error); goto error; } tmp_list = _dbus_list_get_next_link (&tokens, tmp_list); ++i; } argv[argc] = NULL; _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL); _dbus_list_clear (&tokens); if (argcp) *argcp = argc; if (argvp) *argvp = argv; else dbus_free_string_array (argv); return TRUE; error: _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL); _dbus_list_clear (&tokens); return FALSE; } dbus-1.10.6/dbus/dbus-message-util.c0000644000175000017500000016071312602773110017200 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. * Copyright (C) 2002, 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-message-private.h" #include "dbus-marshal-recursive.h" #include "dbus-string.h" #ifdef HAVE_UNIX_FD_PASSING #include "dbus-sysdeps-unix.h" #endif #ifdef __linux__ /* Necessary for the Linux-specific fd leak checking code only */ #include #include #include #include #endif /** * @addtogroup DBusMessage * @{ */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Reads arguments from a message iterator given a variable argument * list. Only arguments of basic type and arrays of fixed-length * basic type may be read with this function. See * dbus_message_get_args() for more details. * * @param iter the message iterator * @param error error to be filled in on failure * @param first_arg_type the first argument type * @param ... location for first argument value, then list of type-location pairs * @returns #FALSE if the error was set */ static dbus_bool_t dbus_message_iter_get_args (DBusMessageIter *iter, DBusError *error, int first_arg_type, ...) { dbus_bool_t retval; va_list var_args; _dbus_return_val_if_fail (iter != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); va_start (var_args, first_arg_type); retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); va_end (var_args); return retval; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include "dbus-message-factory.h" #include #include static int validities_seen[DBUS_VALIDITY_LAST + _DBUS_NEGATIVE_VALIDITY_COUNT]; static void reset_validities_seen (void) { int i; i = 0; while (i < _DBUS_N_ELEMENTS (validities_seen)) { validities_seen[i] = 0; ++i; } } static void record_validity_seen (DBusValidity validity) { validities_seen[validity + _DBUS_NEGATIVE_VALIDITY_COUNT] += 1; } static void print_validities_seen (dbus_bool_t not_seen) { int i; i = 0; while (i < _DBUS_N_ELEMENTS (validities_seen)) { if ((i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_VALIDITY_UNKNOWN || (i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_INVALID_FOR_UNKNOWN_REASON) ; else if ((not_seen && validities_seen[i] == 0) || (!not_seen && validities_seen[i] > 0)) printf ("validity %3d seen %d times\n", i - _DBUS_NEGATIVE_VALIDITY_COUNT, validities_seen[i]); ++i; } } static void check_memleaks (void) { dbus_shutdown (); if (_dbus_get_malloc_blocks_outstanding () != 0) { _dbus_warn ("%d dbus_malloc blocks were not freed in %s\n", _dbus_get_malloc_blocks_outstanding (), __FILE__); _dbus_assert_not_reached ("memleaks"); } } #ifdef __linux__ struct DBusInitialFDs { fd_set set; }; #endif DBusInitialFDs * _dbus_check_fdleaks_enter (void) { #ifdef __linux__ DIR *d; DBusInitialFDs *fds; /* this is plain malloc so it won't interfere with leak checking */ fds = malloc (sizeof (DBusInitialFDs)); _dbus_assert (fds != NULL); /* This works on Linux only */ if ((d = opendir ("/proc/self/fd"))) { struct dirent *de; while ((de = readdir(d))) { long l; char *e = NULL; int fd; if (de->d_name[0] == '.') continue; errno = 0; l = strtol (de->d_name, &e, 10); _dbus_assert (errno == 0 && e && !*e); fd = (int) l; if (fd < 3) continue; if (fd == dirfd (d)) continue; FD_SET (fd, &fds->set); } closedir (d); } return fds; #else return NULL; #endif } void _dbus_check_fdleaks_leave (DBusInitialFDs *fds) { #ifdef __linux__ DIR *d; /* This works on Linux only */ if ((d = opendir ("/proc/self/fd"))) { struct dirent *de; while ((de = readdir(d))) { long l; char *e = NULL; int fd; if (de->d_name[0] == '.') continue; errno = 0; l = strtol (de->d_name, &e, 10); _dbus_assert (errno == 0 && e && !*e); fd = (int) l; if (fd < 3) continue; if (fd == dirfd (d)) continue; if (FD_ISSET (fd, &fds->set)) continue; _dbus_warn ("file descriptor %i leaked in %s.\n", fd, __FILE__); _dbus_assert_not_reached ("fdleaks"); } closedir (d); } free (fds); #else _dbus_assert (fds == NULL); #endif } static dbus_bool_t check_have_valid_message (DBusMessageLoader *loader) { DBusMessage *message; dbus_bool_t retval; message = NULL; retval = FALSE; if (_dbus_message_loader_get_is_corrupted (loader)) { _dbus_warn ("loader corrupted on message that was expected to be valid; invalid reason %d\n", loader->corruption_reason); goto failed; } message = _dbus_message_loader_pop_message (loader); if (message == NULL) { _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n"); goto failed; } if (_dbus_string_get_length (&loader->data) > 0) { _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n"); goto failed; } #if 0 /* FIXME */ /* Verify that we're able to properly deal with the message. * For example, this would detect improper handling of messages * in nonstandard byte order. */ if (!check_message_handling (message)) goto failed; #endif record_validity_seen (DBUS_VALID); retval = TRUE; failed: if (message) dbus_message_unref (message); return retval; } static dbus_bool_t check_invalid_message (DBusMessageLoader *loader, DBusValidity expected_validity) { dbus_bool_t retval; retval = FALSE; if (!_dbus_message_loader_get_is_corrupted (loader)) { _dbus_warn ("loader not corrupted on message that was expected to be invalid\n"); goto failed; } record_validity_seen (loader->corruption_reason); if (expected_validity != DBUS_INVALID_FOR_UNKNOWN_REASON && loader->corruption_reason != expected_validity) { _dbus_warn ("expected message to be corrupted for reason %d and was corrupted for %d instead\n", expected_validity, loader->corruption_reason); goto failed; } retval = TRUE; failed: return retval; } static dbus_bool_t check_incomplete_message (DBusMessageLoader *loader) { DBusMessage *message; dbus_bool_t retval; message = NULL; retval = FALSE; if (_dbus_message_loader_get_is_corrupted (loader)) { _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete), corruption reason %d\n", loader->corruption_reason); goto failed; } message = _dbus_message_loader_pop_message (loader); if (message != NULL) { _dbus_warn ("loaded message that was expected to be incomplete\n"); goto failed; } record_validity_seen (DBUS_VALID_BUT_INCOMPLETE); retval = TRUE; failed: if (message) dbus_message_unref (message); return retval; } static dbus_bool_t check_loader_results (DBusMessageLoader *loader, DBusValidity expected_validity) { if (!_dbus_message_loader_queue_messages (loader)) _dbus_assert_not_reached ("no memory to queue messages"); if (expected_validity == DBUS_VALID) return check_have_valid_message (loader); else if (expected_validity == DBUS_VALID_BUT_INCOMPLETE) return check_incomplete_message (loader); else if (expected_validity == DBUS_VALIDITY_UNKNOWN) { /* here we just know we didn't segfault and that was the * only test. Also, we record that we got coverage * for the validity reason. */ if (_dbus_message_loader_get_is_corrupted (loader)) record_validity_seen (loader->corruption_reason); return TRUE; } else return check_invalid_message (loader, expected_validity); } /** * Loads the message in the given message file. * * @param filename filename to load * @param data string to load message into * @returns #TRUE if the message was loaded */ dbus_bool_t dbus_internal_do_not_use_load_message_file (const DBusString *filename, DBusString *data) { dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; retval = FALSE; _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); if (!_dbus_file_get_contents (data, filename, &error)) { _dbus_warn ("Could not load message file %s: %s\n", _dbus_string_get_const_data (filename), error.message); dbus_error_free (&error); goto failed; } retval = TRUE; failed: return retval; } /** * Tries loading the message in the given message file * and verifies that DBusMessageLoader can handle it. * * @param filename filename to load * @param expected_validity what the message has to be like to return #TRUE * @returns #TRUE if the message has the expected validity */ dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename, DBusValidity expected_validity) { DBusString data; dbus_bool_t retval; retval = FALSE; if (!_dbus_string_init (&data)) _dbus_assert_not_reached ("could not allocate string\n"); if (!dbus_internal_do_not_use_load_message_file (filename, &data)) goto failed; retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); failed: if (!retval) { if (_dbus_string_get_length (&data) > 0) _dbus_verbose_bytes_of_string (&data, 0, _dbus_string_get_length (&data)); _dbus_warn ("Failed message loader test on %s\n", _dbus_string_get_const_data (filename)); } _dbus_string_free (&data); return retval; } /** * Tries loading the given message data. * * * @param data the message data * @param expected_validity what the message has to be like to return #TRUE * @returns #TRUE if the message has the expected validity */ dbus_bool_t dbus_internal_do_not_use_try_message_data (const DBusString *data, DBusValidity expected_validity) { DBusMessageLoader *loader; dbus_bool_t retval; int len; int i; loader = NULL; retval = FALSE; /* Write the data one byte at a time */ loader = _dbus_message_loader_new (); /* check some trivial loader functions */ _dbus_message_loader_ref (loader); _dbus_message_loader_unref (loader); _dbus_message_loader_get_max_message_size (loader); len = _dbus_string_get_length (data); for (i = 0; i < len; i++) { DBusString *buffer; _dbus_message_loader_get_buffer (loader, &buffer); _dbus_string_append_byte (buffer, _dbus_string_get_byte (data, i)); _dbus_message_loader_return_buffer (loader, buffer); } if (!check_loader_results (loader, expected_validity)) goto failed; _dbus_message_loader_unref (loader); loader = NULL; /* Write the data all at once */ loader = _dbus_message_loader_new (); { DBusString *buffer; _dbus_message_loader_get_buffer (loader, &buffer); _dbus_string_copy (data, 0, buffer, _dbus_string_get_length (buffer)); _dbus_message_loader_return_buffer (loader, buffer); } if (!check_loader_results (loader, expected_validity)) goto failed; _dbus_message_loader_unref (loader); loader = NULL; /* Write the data 2 bytes at a time */ loader = _dbus_message_loader_new (); len = _dbus_string_get_length (data); for (i = 0; i < len; i += 2) { DBusString *buffer; _dbus_message_loader_get_buffer (loader, &buffer); _dbus_string_append_byte (buffer, _dbus_string_get_byte (data, i)); if ((i+1) < len) _dbus_string_append_byte (buffer, _dbus_string_get_byte (data, i+1)); _dbus_message_loader_return_buffer (loader, buffer); } if (!check_loader_results (loader, expected_validity)) goto failed; _dbus_message_loader_unref (loader); loader = NULL; retval = TRUE; failed: if (loader) _dbus_message_loader_unref (loader); return retval; } static dbus_bool_t process_test_subdir (const DBusString *test_base_dir, const char *subdir, DBusValidity expected_validity, DBusForeachMessageFileFunc function, void *user_data) { DBusString test_directory; DBusString filename; DBusDirIter *dir; dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; retval = FALSE; dir = NULL; if (!_dbus_string_init (&test_directory)) _dbus_assert_not_reached ("didn't allocate test_directory\n"); _dbus_string_init_const (&filename, subdir); if (!_dbus_string_copy (test_base_dir, 0, &test_directory, 0)) _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); if (!_dbus_concat_dir_and_file (&test_directory, &filename)) _dbus_assert_not_reached ("couldn't allocate full path"); _dbus_string_free (&filename); if (!_dbus_string_init (&filename)) _dbus_assert_not_reached ("didn't allocate filename string\n"); dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { _dbus_warn ("Could not open %s: %s\n", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); goto failed; } printf ("Testing %s:\n", subdir); next: while (_dbus_directory_get_next_file (dir, &filename, &error)) { DBusString full_path; if (!_dbus_string_init (&full_path)) _dbus_assert_not_reached ("couldn't init string"); if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) _dbus_assert_not_reached ("couldn't copy dir to full_path"); if (!_dbus_concat_dir_and_file (&full_path, &filename)) _dbus_assert_not_reached ("couldn't concat file to dir"); if (_dbus_string_ends_with_c_str (&filename, ".message-raw")) ; else { if (_dbus_string_ends_with_c_str (&filename, ".message")) { printf ("SKIP: Could not load %s, message builder language no longer supported\n", _dbus_string_get_const_data (&filename)); } _dbus_verbose ("Skipping non-.message file %s\n", _dbus_string_get_const_data (&filename)); _dbus_string_free (&full_path); goto next; } printf (" %s\n", _dbus_string_get_const_data (&filename)); if (! (*function) (&full_path, expected_validity, user_data)) { _dbus_string_free (&full_path); goto failed; } else _dbus_string_free (&full_path); } if (dbus_error_is_set (&error)) { _dbus_warn ("Could not get next file in %s: %s\n", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); goto failed; } retval = TRUE; failed: if (dir) _dbus_directory_close (dir); _dbus_string_free (&test_directory); _dbus_string_free (&filename); return retval; } /** * Runs the given function on every message file in the test suite. * The function should return #FALSE on test failure or fatal error. * * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data) * @param func the function to run * @param user_data data for function * @returns #FALSE if there's a failure */ dbus_bool_t dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir, DBusForeachMessageFileFunc func, void *user_data) { DBusString test_directory; dbus_bool_t retval; retval = FALSE; _dbus_string_init_const (&test_directory, test_data_dir); if (!process_test_subdir (&test_directory, "valid-messages", DBUS_VALID, func, user_data)) goto failed; check_memleaks (); if (!process_test_subdir (&test_directory, "invalid-messages", DBUS_INVALID_FOR_UNKNOWN_REASON, func, user_data)) goto failed; check_memleaks (); if (!process_test_subdir (&test_directory, "incomplete-messages", DBUS_VALID_BUT_INCOMPLETE, func, user_data)) goto failed; check_memleaks (); retval = TRUE; failed: _dbus_string_free (&test_directory); return retval; } #if 0 #define GET_AND_CHECK(iter, typename, literal) \ do { \ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ _dbus_assert_not_reached ("got wrong argument type from message iter"); \ dbus_message_iter_get_basic (&iter, &v_##typename); \ if (v_##typename != literal) \ _dbus_assert_not_reached ("got wrong value from message iter"); \ } while (0) #define GET_AND_CHECK_STRCMP(iter, typename, literal) \ do { \ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ _dbus_assert_not_reached ("got wrong argument type from message iter"); \ dbus_message_iter_get_basic (&iter, &v_##typename); \ if (strcmp (v_##typename, literal) != 0) \ _dbus_assert_not_reached ("got wrong value from message iter"); \ } while (0) #define GET_AND_CHECK_AND_NEXT(iter, typename, literal) \ do { \ GET_AND_CHECK(iter, typename, literal); \ if (!dbus_message_iter_next (&iter)) \ _dbus_assert_not_reached ("failed to move iter to next"); \ } while (0) #define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal) \ do { \ GET_AND_CHECK_STRCMP(iter, typename, literal); \ if (!dbus_message_iter_next (&iter)) \ _dbus_assert_not_reached ("failed to move iter to next"); \ } while (0) static void message_iter_test (DBusMessage *message) { DBusMessageIter iter, array, array2; const char *v_STRING; double v_DOUBLE; dbus_int16_t v_INT16; dbus_uint16_t v_UINT16; dbus_int32_t v_INT32; dbus_uint32_t v_UINT32; dbus_int64_t v_INT64; dbus_uint64_t v_UINT64; unsigned char v_BYTE; dbus_bool_t v_BOOLEAN; const dbus_int32_t *our_int_array; int len; dbus_message_iter_init (message, &iter); GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string"); GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678); GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e); GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) _dbus_assert_not_reached ("Argument type not an array"); if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE) _dbus_assert_not_reached ("Array type not double"); dbus_message_iter_recurse (&iter, &array); GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5); GET_AND_CHECK (array, DOUBLE, 2.5); if (dbus_message_iter_next (&array)) _dbus_assert_not_reached ("Didn't reach end of array"); if (!dbus_message_iter_next (&iter)) _dbus_assert_not_reached ("Reached end of arguments"); GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) _dbus_assert_not_reached ("no array"); if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32) _dbus_assert_not_reached ("Array type not int32"); /* Empty array */ dbus_message_iter_recurse (&iter, &array); if (dbus_message_iter_next (&array)) _dbus_assert_not_reached ("Didn't reach end of array"); if (!dbus_message_iter_next (&iter)) _dbus_assert_not_reached ("Reached end of arguments"); GET_AND_CHECK (iter, BYTE, 0xF0); if (dbus_message_iter_next (&iter)) _dbus_assert_not_reached ("Didn't reach end of arguments"); } #endif static void verify_test_message (DBusMessage *message) { DBusMessageIter iter; DBusError error = DBUS_ERROR_INIT; dbus_int16_t our_int16; dbus_uint16_t our_uint16; dbus_int32_t our_int; dbus_uint32_t our_uint; const char *our_str; double our_double; double v_DOUBLE; dbus_bool_t our_bool; unsigned char our_byte_1, our_byte_2; const dbus_uint32_t *our_uint32_array = (void*)0xdeadbeef; int our_uint32_array_len; dbus_int32_t *our_int32_array = (void*)0xdeadbeef; int our_int32_array_len; dbus_int64_t our_int64; dbus_uint64_t our_uint64; dbus_int64_t *our_uint64_array = (void*)0xdeadbeef; int our_uint64_array_len; const dbus_int64_t *our_int64_array = (void*)0xdeadbeef; int our_int64_array_len; const double *our_double_array = (void*)0xdeadbeef; int our_double_array_len; const unsigned char *our_byte_array = (void*)0xdeadbeef; int our_byte_array_len; const dbus_bool_t *our_boolean_array = (void*)0xdeadbeef; int our_boolean_array_len; char **our_string_array; int our_string_array_len; dbus_message_iter_init (message, &iter); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_INT16, &our_int16, DBUS_TYPE_UINT16, &our_uint16, DBUS_TYPE_INT32, &our_int, DBUS_TYPE_UINT32, &our_uint, DBUS_TYPE_INT64, &our_int64, DBUS_TYPE_UINT64, &our_uint64, DBUS_TYPE_STRING, &our_str, DBUS_TYPE_DOUBLE, &our_double, DBUS_TYPE_BOOLEAN, &our_bool, DBUS_TYPE_BYTE, &our_byte_1, DBUS_TYPE_BYTE, &our_byte_2, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &our_uint32_array, &our_uint32_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &our_int32_array, &our_int32_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &our_uint64_array, &our_uint64_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &our_int64_array, &our_int64_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &our_double_array, &our_double_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &our_byte_array, &our_byte_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &our_boolean_array, &our_boolean_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array, &our_string_array_len, 0)) { _dbus_warn ("error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); _dbus_assert_not_reached ("Could not get arguments"); } if (our_int16 != -0x123) _dbus_assert_not_reached ("16-bit integers differ!"); if (our_uint16 != 0x123) _dbus_assert_not_reached ("16-bit uints differ!"); if (our_int != -0x12345678) _dbus_assert_not_reached ("integers differ!"); if (our_uint != 0x12300042) _dbus_assert_not_reached ("uints differ!"); if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd)) _dbus_assert_not_reached ("64-bit integers differ!"); if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd)) _dbus_assert_not_reached ("64-bit unsigned integers differ!"); v_DOUBLE = 3.14159; if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double, v_DOUBLE)) _dbus_assert_not_reached ("doubles differ!"); if (strcmp (our_str, "Test string") != 0) _dbus_assert_not_reached ("strings differ!"); if (!our_bool) _dbus_assert_not_reached ("booleans differ"); if (our_byte_1 != 42) _dbus_assert_not_reached ("bytes differ!"); if (our_byte_2 != 24) _dbus_assert_not_reached ("bytes differ!"); if (our_uint32_array_len != 4 || our_uint32_array[0] != 0x12345678 || our_uint32_array[1] != 0x23456781 || our_uint32_array[2] != 0x34567812 || our_uint32_array[3] != 0x45678123) _dbus_assert_not_reached ("uint array differs"); if (our_int32_array_len != 4 || our_int32_array[0] != 0x12345678 || our_int32_array[1] != -0x23456781 || our_int32_array[2] != 0x34567812 || our_int32_array[3] != -0x45678123) _dbus_assert_not_reached ("int array differs"); if (our_uint64_array_len != 4 || our_uint64_array[0] != 0x12345678 || our_uint64_array[1] != 0x23456781 || our_uint64_array[2] != 0x34567812 || our_uint64_array[3] != 0x45678123) _dbus_assert_not_reached ("uint64 array differs"); if (our_int64_array_len != 4 || our_int64_array[0] != 0x12345678 || our_int64_array[1] != -0x23456781 || our_int64_array[2] != 0x34567812 || our_int64_array[3] != -0x45678123) _dbus_assert_not_reached ("int64 array differs"); if (our_double_array_len != 3) _dbus_assert_not_reached ("double array had wrong length"); /* On all IEEE machines (i.e. everything sane) exact equality * should be preserved over the wire */ v_DOUBLE = 0.1234; if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[0], v_DOUBLE)) _dbus_assert_not_reached ("double array had wrong values"); v_DOUBLE = 9876.54321; if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[1], v_DOUBLE)) _dbus_assert_not_reached ("double array had wrong values"); v_DOUBLE = -300.0; if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[2], v_DOUBLE)) _dbus_assert_not_reached ("double array had wrong values"); if (our_byte_array_len != 4) _dbus_assert_not_reached ("byte array had wrong length"); if (our_byte_array[0] != 'a' || our_byte_array[1] != 'b' || our_byte_array[2] != 'c' || our_byte_array[3] != 234) _dbus_assert_not_reached ("byte array had wrong values"); if (our_boolean_array_len != 5) _dbus_assert_not_reached ("bool array had wrong length"); if (our_boolean_array[0] != TRUE || our_boolean_array[1] != FALSE || our_boolean_array[2] != TRUE || our_boolean_array[3] != TRUE || our_boolean_array[4] != FALSE) _dbus_assert_not_reached ("bool array had wrong values"); if (our_string_array_len != 4) _dbus_assert_not_reached ("string array was wrong length"); if (strcmp (our_string_array[0], "Foo") != 0 || strcmp (our_string_array[1], "bar") != 0 || strcmp (our_string_array[2], "") != 0 || strcmp (our_string_array[3], "woo woo woo woo") != 0) _dbus_assert_not_reached ("string array had wrong values"); dbus_free_string_array (our_string_array); if (dbus_message_iter_next (&iter)) _dbus_assert_not_reached ("Didn't reach end of arguments"); } static void verify_test_message_args_ignored (DBusMessage *message) { DBusMessageIter iter; DBusError error = DBUS_ERROR_INIT; dbus_uint32_t our_uint; DBusInitialFDs *initial_fds; initial_fds = _dbus_check_fdleaks_enter (); /* parse with empty signature: "" */ dbus_message_iter_init (message, &iter); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_INVALID)) { _dbus_warn ("error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); } else { _dbus_assert (!dbus_error_is_set (&error)); _dbus_verbose ("arguments ignored.\n"); } /* parse with shorter signature: "u" */ dbus_message_iter_init (message, &iter); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_UINT32, &our_uint, DBUS_TYPE_INVALID)) { _dbus_warn ("error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); } else { _dbus_assert (!dbus_error_is_set (&error)); _dbus_verbose ("arguments ignored.\n"); } _dbus_check_fdleaks_leave (initial_fds); } static void verify_test_message_memleak (DBusMessage *message) { DBusMessageIter iter; DBusError error = DBUS_ERROR_INIT; dbus_uint32_t our_uint1; dbus_uint32_t our_uint2; dbus_uint32_t our_uint3; char **our_string_array1; int our_string_array_len1; char **our_string_array2; int our_string_array_len2; #ifdef HAVE_UNIX_FD_PASSING int our_unix_fd1; int our_unix_fd2; #endif DBusInitialFDs *initial_fds; initial_fds = _dbus_check_fdleaks_enter (); /* parse with wrong signature: "uashuu" */ dbus_error_free (&error); dbus_message_iter_init (message, &iter); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_UINT32, &our_uint1, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array1, &our_string_array_len1, #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &our_unix_fd1, #endif DBUS_TYPE_UINT32, &our_uint2, DBUS_TYPE_UINT32, &our_uint3, DBUS_TYPE_INVALID)) { _dbus_verbose ("expected error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); /* ensure array of string and unix fd not leaked */ _dbus_assert (our_string_array1 == NULL); #ifdef HAVE_UNIX_FD_PASSING _dbus_assert (our_unix_fd1 == -1); #endif } else { _dbus_warn ("error: parse with wrong signature: 'uashuu'.\n"); } /* parse with wrong signature: "uashuashu" */ dbus_message_iter_init (message, &iter); dbus_error_free (&error); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_UINT32, &our_uint1, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array1, &our_string_array_len1, #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &our_unix_fd1, #endif DBUS_TYPE_UINT32, &our_uint2, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array2, &our_string_array_len2, #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &our_unix_fd2, #endif DBUS_TYPE_UINT32, &our_uint3, DBUS_TYPE_INVALID)) { _dbus_verbose ("expected error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); /* ensure array of string and unix fd not leaked */ _dbus_assert (our_string_array1 == NULL); _dbus_assert (our_string_array2 == NULL); #ifdef HAVE_UNIX_FD_PASSING _dbus_assert (our_unix_fd1 == -1); _dbus_assert (our_unix_fd2 == -1); #endif } else { _dbus_warn ("error: parse with wrong signature: 'uashuashu'.\n"); } /* parse with correct signature: "uashuash" */ dbus_message_iter_init (message, &iter); dbus_error_free (&error); if (!dbus_message_iter_get_args (&iter, &error, DBUS_TYPE_UINT32, &our_uint1, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array1, &our_string_array_len1, #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &our_unix_fd1, #endif DBUS_TYPE_UINT32, &our_uint2, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &our_string_array2, &our_string_array_len2, #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &our_unix_fd2, #endif DBUS_TYPE_INVALID)) { _dbus_warn ("error: %s - %s\n", error.name, (error.message != NULL) ? error.message : "no message"); _dbus_assert_not_reached ("Could not get arguments"); } else { dbus_free_string_array (our_string_array1); dbus_free_string_array (our_string_array2); #ifdef HAVE_UNIX_FD_PASSING _dbus_close (our_unix_fd1, &error); _dbus_close (our_unix_fd2, &error); #endif } _dbus_check_fdleaks_leave (initial_fds); } /** * @ingroup DBusMessageInternals * Unit test for DBusMessage. * * @returns #TRUE on success. */ dbus_bool_t _dbus_message_test (const char *test_data_dir) { DBusMessage *message, *message_without_unix_fds; DBusMessageLoader *loader; int i; const char *data; DBusMessage *copy; const char *name1; const char *name2; const dbus_uint32_t our_uint32_array[] = { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; const dbus_int32_t our_int32_array[] = { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; const dbus_uint64_t our_uint64_array[] = { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; const dbus_int64_t our_int64_array[] = { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" }; const char *our_string_array1[] = { "foo", "Bar", "", "Woo woo Woo woo" }; const char **v_ARRAY_STRING = our_string_array; const char **v1_ARRAY_STRING = our_string_array1; const double our_double_array[] = { 0.1234, 9876.54321, -300.0 }; const double *v_ARRAY_DOUBLE = our_double_array; const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 }; const unsigned char *v_ARRAY_BYTE = our_byte_array; const dbus_bool_t our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE }; const dbus_bool_t *v_ARRAY_BOOLEAN = our_boolean_array; char sig[64]; const char *s; const char *v_STRING; double v_DOUBLE; dbus_int16_t v_INT16; dbus_uint16_t v_UINT16; dbus_int32_t v_INT32; dbus_uint32_t v_UINT32; dbus_uint32_t v1_UINT32; dbus_int64_t v_INT64; dbus_uint64_t v_UINT64; unsigned char v_BYTE; unsigned char v2_BYTE; dbus_bool_t v_BOOLEAN; DBusMessageIter iter, array_iter, struct_iter; #ifdef HAVE_UNIX_FD_PASSING int v_UNIX_FD; int v1_UNIX_FD; #endif char **decomposed; DBusInitialFDs *initial_fds; dbus_bool_t ok; char basic_types[] = DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_BOOLEAN_AS_STRING \ DBUS_TYPE_INT16_AS_STRING \ DBUS_TYPE_INT32_AS_STRING \ DBUS_TYPE_INT64_AS_STRING \ DBUS_TYPE_UINT16_AS_STRING \ DBUS_TYPE_UINT32_AS_STRING \ DBUS_TYPE_UINT64_AS_STRING \ DBUS_TYPE_DOUBLE_AS_STRING \ DBUS_TYPE_STRING_AS_STRING; initial_fds = _dbus_check_fdleaks_enter (); message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", "Foo.TestInterface", "TestMethod"); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", "TestMethod")); _dbus_assert (strcmp (dbus_message_get_path (message), "/org/freedesktop/TestPath") == 0); dbus_message_set_serial (message, 1234); /* string length including nul byte not a multiple of 4 */ if (!dbus_message_set_sender (message, "org.foo.bar1")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); dbus_message_set_reply_serial (message, 5678); _dbus_verbose_bytes_of_string (&message->header.data, 0, _dbus_string_get_length (&message->header.data)); _dbus_verbose_bytes_of_string (&message->body, 0, _dbus_string_get_length (&message->body)); if (!dbus_message_set_sender (message, NULL)) _dbus_assert_not_reached ("out of memory"); _dbus_verbose_bytes_of_string (&message->header.data, 0, _dbus_string_get_length (&message->header.data)); _dbus_verbose_bytes_of_string (&message->body, 0, _dbus_string_get_length (&message->body)); _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); _dbus_assert (dbus_message_get_serial (message) == 1234); _dbus_assert (dbus_message_get_reply_serial (message) == 5678); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); _dbus_assert (dbus_message_get_no_reply (message) == FALSE); dbus_message_set_no_reply (message, TRUE); _dbus_assert (dbus_message_get_no_reply (message) == TRUE); dbus_message_set_no_reply (message, FALSE); _dbus_assert (dbus_message_get_no_reply (message) == FALSE); /* Set/get some header fields */ if (!dbus_message_set_path (message, "/foo")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_path (message), "/foo") == 0); if (!dbus_message_set_interface (message, "org.Foo")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_interface (message), "org.Foo") == 0); if (!dbus_message_set_member (message, "Bar")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_member (message), "Bar") == 0); /* Set/get them with longer values */ if (!dbus_message_set_path (message, "/foo/bar")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_path (message), "/foo/bar") == 0); if (!dbus_message_set_interface (message, "org.Foo.Bar")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_interface (message), "org.Foo.Bar") == 0); if (!dbus_message_set_member (message, "BarFoo")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_member (message), "BarFoo") == 0); /* Realloc shorter again */ if (!dbus_message_set_path (message, "/foo")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_path (message), "/foo") == 0); if (!dbus_message_set_interface (message, "org.Foo")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_interface (message), "org.Foo") == 0); if (!dbus_message_set_member (message, "Bar")) _dbus_assert_not_reached ("out of memory"); _dbus_assert (strcmp (dbus_message_get_member (message), "Bar") == 0); /* Path decomposing */ dbus_message_set_path (message, NULL); dbus_message_get_path_decomposed (message, &decomposed); _dbus_assert (decomposed == NULL); dbus_free_string_array (decomposed); dbus_message_set_path (message, "/"); dbus_message_get_path_decomposed (message, &decomposed); _dbus_assert (decomposed != NULL); _dbus_assert (decomposed[0] == NULL); dbus_free_string_array (decomposed); dbus_message_set_path (message, "/a/b"); dbus_message_get_path_decomposed (message, &decomposed); _dbus_assert (decomposed != NULL); _dbus_assert (strcmp (decomposed[0], "a") == 0); _dbus_assert (strcmp (decomposed[1], "b") == 0); _dbus_assert (decomposed[2] == NULL); dbus_free_string_array (decomposed); dbus_message_set_path (message, "/spam/eggs"); dbus_message_get_path_decomposed (message, &decomposed); _dbus_assert (decomposed != NULL); _dbus_assert (strcmp (decomposed[0], "spam") == 0); _dbus_assert (strcmp (decomposed[1], "eggs") == 0); _dbus_assert (decomposed[2] == NULL); dbus_free_string_array (decomposed); dbus_message_unref (message); /* Test the vararg functions */ message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", "Foo.TestInterface", "TestMethod"); dbus_message_set_serial (message, 1); dbus_message_set_reply_serial (message, 5678); v_INT16 = -0x123; v_UINT16 = 0x123; v_INT32 = -0x12345678; v_UINT32 = 0x12300042; v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd); v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd); v_STRING = "Test string"; v_DOUBLE = 3.14159; v_BOOLEAN = TRUE; v_BYTE = 42; v2_BYTE = 24; #ifdef HAVE_UNIX_FD_PASSING v_UNIX_FD = 1; v1_UNIX_FD = 2; #endif dbus_message_append_args (message, DBUS_TYPE_INT16, &v_INT16, DBUS_TYPE_UINT16, &v_UINT16, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_UINT32, &v_UINT32, DBUS_TYPE_INT64, &v_INT64, DBUS_TYPE_UINT64, &v_UINT64, DBUS_TYPE_STRING, &v_STRING, DBUS_TYPE_DOUBLE, &v_DOUBLE, DBUS_TYPE_BOOLEAN, &v_BOOLEAN, DBUS_TYPE_BYTE, &v_BYTE, DBUS_TYPE_BYTE, &v2_BYTE, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32, _DBUS_N_ELEMENTS (our_uint32_array), DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32, _DBUS_N_ELEMENTS (our_int32_array), DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64, _DBUS_N_ELEMENTS (our_uint64_array), DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64, _DBUS_N_ELEMENTS (our_int64_array), DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE, _DBUS_N_ELEMENTS (our_double_array), DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE, _DBUS_N_ELEMENTS (our_byte_array), DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, _DBUS_N_ELEMENTS (our_boolean_array), DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING, _DBUS_N_ELEMENTS (our_string_array), DBUS_TYPE_INVALID); i = 0; sig[i++] = DBUS_TYPE_INT16; sig[i++] = DBUS_TYPE_UINT16; sig[i++] = DBUS_TYPE_INT32; sig[i++] = DBUS_TYPE_UINT32; sig[i++] = DBUS_TYPE_INT64; sig[i++] = DBUS_TYPE_UINT64; sig[i++] = DBUS_TYPE_STRING; sig[i++] = DBUS_TYPE_DOUBLE; sig[i++] = DBUS_TYPE_BOOLEAN; sig[i++] = DBUS_TYPE_BYTE; sig[i++] = DBUS_TYPE_BYTE; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_UINT32; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_INT32; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_UINT64; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_INT64; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_DOUBLE; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_BYTE; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_BOOLEAN; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_STRING; message_without_unix_fds = dbus_message_copy(message); _dbus_assert(message_without_unix_fds); #ifdef HAVE_UNIX_FD_PASSING dbus_message_append_args (message, DBUS_TYPE_UNIX_FD, &v_UNIX_FD, DBUS_TYPE_INVALID); sig[i++] = DBUS_TYPE_UNIX_FD; #endif sig[i++] = DBUS_TYPE_INVALID; _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); _dbus_verbose ("HEADER\n"); _dbus_verbose_bytes_of_string (&message->header.data, 0, _dbus_string_get_length (&message->header.data)); _dbus_verbose ("BODY\n"); _dbus_verbose_bytes_of_string (&message->body, 0, _dbus_string_get_length (&message->body)); _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n", sig, dbus_message_get_signature (message)); s = dbus_message_get_signature (message); _dbus_assert (dbus_message_has_signature (message, sig)); _dbus_assert (strcmp (s, sig) == 0); verify_test_message (message); copy = dbus_message_copy (message); _dbus_assert (dbus_message_get_reply_serial (message) == dbus_message_get_reply_serial (copy)); _dbus_assert (message->header.padding == copy->header.padding); _dbus_assert (_dbus_string_get_length (&message->header.data) == _dbus_string_get_length (©->header.data)); _dbus_assert (_dbus_string_get_length (&message->body) == _dbus_string_get_length (©->body)); verify_test_message (copy); name1 = dbus_message_get_interface (message); name2 = dbus_message_get_interface (copy); _dbus_assert (strcmp (name1, name2) == 0); name1 = dbus_message_get_member (message); name2 = dbus_message_get_member (copy); _dbus_assert (strcmp (name1, name2) == 0); dbus_message_unref (copy); /* Message loader test */ dbus_message_lock (message); loader = _dbus_message_loader_new (); /* check ref/unref */ _dbus_message_loader_ref (loader); _dbus_message_loader_unref (loader); /* Write the header data one byte at a time */ data = _dbus_string_get_const_data (&message->header.data); for (i = 0; i < _dbus_string_get_length (&message->header.data); i++) { DBusString *buffer; _dbus_message_loader_get_buffer (loader, &buffer); _dbus_string_append_byte (buffer, data[i]); _dbus_message_loader_return_buffer (loader, buffer); } /* Write the body data one byte at a time */ data = _dbus_string_get_const_data (&message->body); for (i = 0; i < _dbus_string_get_length (&message->body); i++) { DBusString *buffer; _dbus_message_loader_get_buffer (loader, &buffer); _dbus_string_append_byte (buffer, data[i]); _dbus_message_loader_return_buffer (loader, buffer); } #ifdef HAVE_UNIX_FD_PASSING { int *unix_fds; unsigned n_unix_fds; /* Write unix fd */ _dbus_message_loader_get_unix_fds(loader, &unix_fds, &n_unix_fds); _dbus_assert(n_unix_fds > 0); _dbus_assert(message->n_unix_fds == 1); unix_fds[0] = _dbus_dup(message->unix_fds[0], NULL); _dbus_assert(unix_fds[0] >= 0); _dbus_message_loader_return_unix_fds(loader, unix_fds, 1); } #endif dbus_message_unref (message); /* Now pop back the message */ if (!_dbus_message_loader_queue_messages (loader)) _dbus_assert_not_reached ("no memory to queue messages"); if (_dbus_message_loader_get_is_corrupted (loader)) _dbus_assert_not_reached ("message loader corrupted"); message = _dbus_message_loader_pop_message (loader); if (!message) _dbus_assert_not_reached ("received a NULL message"); if (dbus_message_get_reply_serial (message) != 5678) _dbus_assert_not_reached ("reply serial fields differ"); dbus_message_unref (message); /* ovveride the serial, since it was reset by dbus_message_copy() */ dbus_message_set_serial(message_without_unix_fds, 8901); dbus_message_lock (message_without_unix_fds); verify_test_message (message_without_unix_fds); { /* Marshal and demarshal the message. */ DBusMessage *message2; DBusError error = DBUS_ERROR_INIT; char *marshalled = NULL; int len = 0; char garbage_header[DBUS_MINIMUM_HEADER_SIZE] = "xxx"; if (!dbus_message_marshal (message_without_unix_fds, &marshalled, &len)) _dbus_assert_not_reached ("failed to marshal message"); _dbus_assert (len != 0); _dbus_assert (marshalled != NULL); _dbus_assert (dbus_message_demarshal_bytes_needed (marshalled, len) == len); message2 = dbus_message_demarshal (marshalled, len, &error); _dbus_assert (message2 != NULL); _dbus_assert (!dbus_error_is_set (&error)); verify_test_message (message2); dbus_message_unref (message2); dbus_free (marshalled); /* Demarshal invalid message. */ message2 = dbus_message_demarshal ("invalid", 7, &error); _dbus_assert (message2 == NULL); _dbus_assert (dbus_error_is_set (&error)); dbus_error_free (&error); /* Demarshal invalid (empty) message. */ message2 = dbus_message_demarshal ("", 0, &error); _dbus_assert (message2 == NULL); _dbus_assert (dbus_error_is_set (&error)); dbus_error_free (&error); /* Bytes needed to demarshal empty message: 0 (more) */ _dbus_assert (dbus_message_demarshal_bytes_needed ("", 0) == 0); /* Bytes needed to demarshal invalid message: -1 (error). */ _dbus_assert (dbus_message_demarshal_bytes_needed (garbage_header, DBUS_MINIMUM_HEADER_SIZE) == -1); } dbus_message_unref (message_without_unix_fds); _dbus_message_loader_unref (loader); check_memleaks (); _dbus_check_fdleaks_leave (initial_fds); initial_fds = _dbus_check_fdleaks_enter (); /* Test enumeration of array elements */ for (i = strlen (basic_types) - 1; i > 0; i--) { DBusBasicValue val; int some; char* signature = _dbus_strdup ("?"); signature[0] = basic_types[i]; s = "SomeThingToSay"; memset (&val, '\0', sizeof (val)); message = dbus_message_new_method_call ("de.ende.test", "/de/ende/test", "de.ende.Test", "ArtistName"); _dbus_assert (message != NULL); dbus_message_iter_init_append (message, &iter); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, signature, &array_iter); for (some = 0; some < 3; some++) { if (basic_types[i] == DBUS_TYPE_STRING) dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &s); else dbus_message_iter_append_basic (&array_iter, basic_types[i], &val); } dbus_message_iter_close_container (&iter, &array_iter); dbus_message_iter_init (message, &iter); _dbus_assert (dbus_message_iter_get_element_count (&iter) == some); dbus_message_unref (message); dbus_free (signature); } /* Array of structs */ message = dbus_message_new_method_call ("de.ende.test", "/de/ende/test", "de.ende.Test", "ArtistName"); _dbus_assert (message != NULL); dbus_message_iter_init_append (message, &iter); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, &array_iter); dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter); s = "SpamAndEggs"; dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &s); dbus_message_iter_close_container (&array_iter, &struct_iter); dbus_message_iter_close_container (&iter, &array_iter); dbus_message_iter_init (message, &iter); _dbus_assert (dbus_message_iter_get_element_count (&iter) == 1); dbus_message_unref (message); check_memleaks (); /* Check that we can abandon a container */ message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", "Foo.TestInterface", "Method"); dbus_message_iter_init_append (message, &iter); ok = dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING), &array_iter); _dbus_assert (ok); ok = dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter); _dbus_assert (ok); s = "peaches"; ok = dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &s); _dbus_assert (ok); /* uh-oh, error, try and unwind */ dbus_message_iter_abandon_container (&array_iter, &struct_iter); dbus_message_iter_abandon_container (&array_iter, &iter); dbus_message_unref (message); /* Check we should not leak array of string or unix fd, fd.o#21259 */ message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", "Foo.TestInterface", "Method"); /* signature "uashuash" */ dbus_message_append_args (message, DBUS_TYPE_UINT32, &v_UINT32, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING, _DBUS_N_ELEMENTS (our_string_array), #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &v_UNIX_FD, #endif DBUS_TYPE_UINT32, &v1_UINT32, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v1_ARRAY_STRING, _DBUS_N_ELEMENTS (our_string_array1), #ifdef HAVE_UNIX_FD_PASSING DBUS_TYPE_UNIX_FD, &v1_UNIX_FD, #endif DBUS_TYPE_INVALID); i = 0; sig[i++] = DBUS_TYPE_UINT32; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_STRING; #ifdef HAVE_UNIX_FD_PASSING sig[i++] = DBUS_TYPE_UNIX_FD; #endif sig[i++] = DBUS_TYPE_UINT32; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_STRING; #ifdef HAVE_UNIX_FD_PASSING sig[i++] = DBUS_TYPE_UNIX_FD; #endif sig[i++] = DBUS_TYPE_INVALID; _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); verify_test_message_args_ignored (message); verify_test_message_memleak (message); dbus_message_unref (message); /* Load all the sample messages from the message factory */ { DBusMessageDataIter diter; DBusMessageData mdata; int count; reset_validities_seen (); count = 0; _dbus_message_data_iter_init (&diter); while (_dbus_message_data_iter_get_and_next (&diter, &mdata)) { if (!dbus_internal_do_not_use_try_message_data (&mdata.data, mdata.expected_validity)) { _dbus_warn ("expected validity %d and did not get it\n", mdata.expected_validity); _dbus_assert_not_reached ("message data failed"); } _dbus_message_data_free (&mdata); count += 1; } printf ("%d sample messages tested\n", count); print_validities_seen (FALSE); print_validities_seen (TRUE); } check_memleaks (); _dbus_check_fdleaks_leave (initial_fds); /* Now load every message in test_data_dir if we have one */ if (test_data_dir == NULL) return TRUE; initial_fds = _dbus_check_fdleaks_enter (); if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir, (DBusForeachMessageFileFunc) dbus_internal_do_not_use_try_message_file, NULL)) _dbus_assert_not_reached ("foreach_message_file test failed"); _dbus_check_fdleaks_leave (initial_fds); return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-message-factory.h0000644000175000017500000000351112602773110017667 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-factory.h Generator of valid and invalid message data for test suite * * Copyright (C) 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MESSAGE_FACTORY_H #define DBUS_MESSAGE_FACTORY_H #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include #include #include DBUS_BEGIN_DECLS typedef struct { DBusValidity expected_validity; DBusString data; } DBusMessageData; #define _DBUS_MESSAGE_DATA_MAX_NESTING 10 typedef struct { int sequence_nos[_DBUS_MESSAGE_DATA_MAX_NESTING]; int depth; int count; } DBusMessageDataIter; void _dbus_message_data_free (DBusMessageData *data); void _dbus_message_data_iter_init (DBusMessageDataIter *iter); dbus_bool_t _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter, DBusMessageData *data); DBUS_END_DECLS #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ #endif /* DBUS_MESSAGE_FACTORY_H */ dbus-1.10.6/dbus/dbus-message-factory.c0000644000175000017500000011427712602773110017676 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-factory.c Generator of valid and invalid message data for test suite * * Copyright (C) 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #ifndef DOXYGEN_SHOULD_SKIP_THIS #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-message-factory.h" #include "dbus-message-private.h" #include "dbus-signature.h" #include "dbus-test.h" #include typedef enum { CHANGE_TYPE_ADJUST, CHANGE_TYPE_ABSOLUTE } ChangeType; #define BYTE_ORDER_OFFSET 0 #define TYPE_OFFSET 1 #define BODY_LENGTH_OFFSET 4 #define FIELDS_ARRAY_LENGTH_OFFSET 12 static void iter_recurse (DBusMessageDataIter *iter) { iter->depth += 1; _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING); _dbus_assert (iter->sequence_nos[iter->depth] >= 0); } static int iter_get_sequence (DBusMessageDataIter *iter) { _dbus_assert (iter->sequence_nos[iter->depth] >= 0); return iter->sequence_nos[iter->depth]; } static void iter_set_sequence (DBusMessageDataIter *iter, int sequence) { _dbus_assert (sequence >= 0); iter->sequence_nos[iter->depth] = sequence; } static void iter_unrecurse (DBusMessageDataIter *iter) { iter->depth -= 1; _dbus_assert (iter->depth >= 0); } static void iter_next (DBusMessageDataIter *iter) { iter->sequence_nos[iter->depth] += 1; } static dbus_bool_t iter_first_in_series (DBusMessageDataIter *iter) { int i; i = iter->depth; while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) { if (iter->sequence_nos[i] != 0) return FALSE; ++i; } return TRUE; } typedef dbus_bool_t (* DBusInnerGeneratorFunc) (DBusMessageDataIter *iter, DBusMessage **message_p); typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity); static void set_reply_serial (DBusMessage *message) { if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_reply_serial (message, 100)) _dbus_assert_not_reached ("oom"); } static dbus_bool_t generate_trivial_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; switch (iter_get_sequence (iter)) { case 0: message = dbus_message_new_method_call ("org.freedesktop.TextEditor", "/foo/bar", "org.freedesktop.DocumentFactory", "Create"); break; case 1: message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); set_reply_serial (message); break; case 2: message = dbus_message_new_signal ("/foo/bar", "org.freedesktop.DocumentFactory", "Created"); break; case 3: message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (!dbus_message_set_error_name (message, "org.freedesktop.TestErrorName")) _dbus_assert_not_reached ("oom"); { DBusMessageIter iter; const char *v_STRING = "This is an error"; dbus_message_iter_init_append (message, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) _dbus_assert_not_reached ("oom"); } set_reply_serial (message); break; default: return FALSE; } if (message == NULL) _dbus_assert_not_reached ("oom"); *message_p = message; return TRUE; } static dbus_bool_t generate_many_bodies_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; DBusString signature; DBusString body; char byte_order; /* Keeping this small makes things go faster */ message = dbus_message_new_method_call ("o.z.F", "/", "o.z.B", "Nah"); if (message == NULL) _dbus_assert_not_reached ("oom"); byte_order = _dbus_header_get_byte_order (&message->header); set_reply_serial (message); if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter), byte_order, &signature, &body)) { const char *v_SIGNATURE; v_SIGNATURE = _dbus_string_get_const_data (&signature); if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_SIGNATURE)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_move (&body, 0, &message->body, 0)) _dbus_assert_not_reached ("oom"); _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET, _dbus_string_get_length (&message->body), byte_order); *message_p = message; } else { dbus_message_unref (message); *message_p = NULL; } _dbus_string_free (&signature); _dbus_string_free (&body); return *message_p != NULL; } static void generate_from_message (DBusString *data, DBusValidity *expected_validity, DBusMessage *message) { dbus_message_set_serial (message, 1); dbus_message_lock (message); *expected_validity = DBUS_VALID; /* move for efficiency, since we'll nuke the message anyway */ if (!_dbus_string_move (&message->header.data, 0, data, 0)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_copy (&message->body, 0, data, _dbus_string_get_length (data))) _dbus_assert_not_reached ("oom"); } static dbus_bool_t generate_outer (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity, DBusInnerGeneratorFunc func) { DBusMessage *message; message = NULL; if (!(*func)(iter, &message)) return FALSE; iter_next (iter); _dbus_assert (message != NULL); generate_from_message (data, expected_validity, message); dbus_message_unref (message); return TRUE; } static dbus_bool_t generate_trivial (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { return generate_outer (iter, data, expected_validity, generate_trivial_inner); } static dbus_bool_t generate_many_bodies (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { return generate_outer (iter, data, expected_validity, generate_many_bodies_inner); } static DBusMessage* simple_method_call (void) { DBusMessage *message; /* Keeping this small makes stuff go faster */ message = dbus_message_new_method_call ("o.b.Q", "/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; } static DBusMessage* simple_signal (void) { DBusMessage *message; message = dbus_message_new_signal ("/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; } static DBusMessage* simple_method_return (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); if (message == NULL) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; } static DBusMessage* simple_error (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_error_name (message, "foo.bar")) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; } static DBusMessage* message_with_nesting_levels (int levels) { DBusMessage *message; dbus_int32_t v_INT32; DBusMessageIter *parents; DBusMessageIter *children; int i; /* If levels is higher it breaks sig_refcount in DBusMessageRealIter * in dbus-message.c, this assert is just to help you know you need * to fix that if you hit it */ _dbus_assert (levels < 256); parents = dbus_new(DBusMessageIter, levels + 1); children = dbus_new(DBusMessageIter, levels + 1); v_INT32 = 42; message = simple_method_call (); i = 0; dbus_message_iter_init_append (message, &parents[i]); while (i < levels) { dbus_message_iter_open_container (&parents[i], DBUS_TYPE_VARIANT, i == (levels - 1) ? DBUS_TYPE_INT32_AS_STRING : DBUS_TYPE_VARIANT_AS_STRING, &children[i]); ++i; parents[i] = children[i-1]; } --i; dbus_message_iter_append_basic (&children[i], DBUS_TYPE_INT32, &v_INT32); while (i >= 0) { dbus_message_iter_close_container (&parents[i], &children[i]); --i; } dbus_free(parents); dbus_free(children); return message; } static dbus_bool_t generate_special (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int item_seq; DBusMessage *message; int pos; dbus_int32_t v_INT32; _dbus_assert (_dbus_string_get_length (data) == 0); message = NULL; pos = -1; v_INT32 = 42; item_seq = iter_get_sequence (iter); if (item_seq == 0) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); /* set an invalid typecode */ _dbus_string_set_byte (data, pos + 1, '$'); *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE; } else if (item_seq == 1) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2]; const char *v_STRING; int i; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) { long_sig[i] = DBUS_TYPE_ARRAY; ++i; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; } else if (item_seq == 2) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4]; const char *v_STRING; int i; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) { long_sig[i] = DBUS_STRUCT_BEGIN_CHAR; ++i; } long_sig[i] = DBUS_TYPE_INT32; ++i; while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3)) { long_sig[i] = DBUS_STRUCT_END_CHAR; ++i; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; } else if (item_seq == 3) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; } else if (item_seq == 4) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR); *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; } else if (item_seq == 5) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR); *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; } else if (item_seq == 6) { message = simple_method_call (); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID); *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE; } else if (item_seq == 7) { /* Messages of unknown type are considered valid */ message = simple_method_call (); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, TYPE_OFFSET, 100); *expected_validity = DBUS_VALID; } else if (item_seq == 8) { char byte_order; message = simple_method_call (); byte_order = _dbus_header_get_byte_order (&message->header); generate_from_message (data, expected_validity, message); _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, byte_order); _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET, DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, byte_order); *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG; } else if (item_seq == 9) { const char *v_STRING = "not a valid bus name"; message = simple_method_call (); if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING, &v_STRING)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_BAD_SENDER; } else if (item_seq == 10) { message = simple_method_call (); if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE; } else if (item_seq == 11) { message = simple_method_call (); if (!dbus_message_set_path (message, DBUS_PATH_LOCAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_USES_LOCAL_PATH; } else if (item_seq == 12) { /* Method calls don't have to have interface */ message = simple_method_call (); if (!dbus_message_set_interface (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_VALID; } else if (item_seq == 13) { /* Signals require an interface */ message = simple_signal (); if (!dbus_message_set_interface (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_INTERFACE; } else if (item_seq == 14) { message = simple_method_return (); if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL; } else if (item_seq == 15) { message = simple_error (); if (!dbus_message_set_error_name (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME; } else if (item_seq == 16) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+10]; const char *v_STRING; int i; int n_begins; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3)) { long_sig[i] = DBUS_TYPE_ARRAY; ++i; long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR; ++i; long_sig[i] = DBUS_TYPE_INT32; ++i; } n_begins = i / 3; long_sig[i] = DBUS_TYPE_INT32; ++i; while (n_begins > 0) { long_sig[i] = DBUS_DICT_ENTRY_END_CHAR; ++i; n_begins -= 1; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; } else if (item_seq == 17) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; } else if (item_seq == 18) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; } else if (item_seq == 19) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; } else if (item_seq == 20) { /* 64 levels of nesting is OK */ message = message_with_nesting_levels(64); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_VALID; } else if (item_seq == 21) { /* 65 levels of nesting is not OK */ message = message_with_nesting_levels(65); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_NESTED_TOO_DEEPLY; } else { return FALSE; } if (message) dbus_message_unref (message); iter_next (iter); return TRUE; } static dbus_bool_t generate_wrong_length (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 }; int adjust; int len_seq; restart: len_seq = iter_get_sequence (iter); if (len_seq == _DBUS_N_ELEMENTS (lengths)) return FALSE; _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths)); iter_recurse (iter); if (!generate_many_bodies (iter, data, expected_validity)) { iter_set_sequence (iter, 0); /* reset to first body */ iter_unrecurse (iter); iter_next (iter); /* next length adjustment */ goto restart; } iter_unrecurse (iter); adjust = lengths[len_seq]; if (adjust < 0) { if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE) _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE); else _dbus_string_shorten (data, - adjust); *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON; } else { if (!_dbus_string_lengthen (data, adjust)) _dbus_assert_not_reached ("oom"); *expected_validity = DBUS_INVALID_TOO_MUCH_DATA; } /* Fixup lengths */ { int old_body_len; int new_body_len; int byte_order; _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); old_body_len = _dbus_marshal_read_uint32 (data, BODY_LENGTH_OFFSET, byte_order, NULL); _dbus_assert (old_body_len < _dbus_string_get_length (data)); new_body_len = old_body_len + adjust; if (new_body_len < 0) { new_body_len = 0; /* we just munged the header, and aren't sure how */ *expected_validity = DBUS_VALIDITY_UNKNOWN; } _dbus_verbose ("changing body len from %u to %u by adjust %d\n", old_body_len, new_body_len, adjust); _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, new_body_len, byte_order); } return TRUE; } static dbus_bool_t generate_byte_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int byte_seq; int v_BYTE; /* This is a little convoluted to make the bodies the * outer loop and each byte of each body the inner * loop */ restart: if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; iter_recurse (iter); byte_seq = iter_get_sequence (iter); iter_next (iter); iter_unrecurse (iter); if (byte_seq == _dbus_string_get_length (data)) { _dbus_string_set_length (data, 0); /* reset byte count */ iter_recurse (iter); iter_set_sequence (iter, 0); iter_unrecurse (iter); goto restart; } else { /* Undo the "next" in generate_many_bodies */ iter_set_sequence (iter, iter_get_sequence (iter) - 1); } _dbus_assert (byte_seq < _dbus_string_get_length (data)); v_BYTE = _dbus_string_get_byte (data, byte_seq); v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */ _dbus_string_set_byte (data, byte_seq, v_BYTE); *expected_validity = DBUS_VALIDITY_UNKNOWN; return TRUE; } #if 0 /* This is really expensive and doesn't add too much coverage */ static dbus_bool_t find_next_typecode (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int body_seq; int byte_seq; int base_depth; base_depth = iter->depth; restart: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); body_seq = iter_get_sequence (iter); if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; /* Undo the "next" in generate_many_bodies */ iter_set_sequence (iter, body_seq); iter_recurse (iter); while (TRUE) { _dbus_assert (iter->depth == (base_depth + 1)); byte_seq = iter_get_sequence (iter); _dbus_assert (byte_seq <= _dbus_string_get_length (data)); if (byte_seq == _dbus_string_get_length (data)) { /* reset byte count */ iter_set_sequence (iter, 0); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); iter_next (iter); /* go to the next body */ goto restart; } _dbus_assert (byte_seq < _dbus_string_get_length (data)); if (dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq))) break; else iter_next (iter); } _dbus_assert (byte_seq == iter_get_sequence (iter)); _dbus_assert (byte_seq < _dbus_string_get_length (data)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); return TRUE; } static const int typecodes[] = { DBUS_TYPE_INVALID, DBUS_TYPE_BYTE, DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT16, DBUS_TYPE_UINT16, DBUS_TYPE_INT32, DBUS_TYPE_UINT32, DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE, DBUS_TYPE_STRING, DBUS_TYPE_OBJECT_PATH, DBUS_TYPE_SIGNATURE, DBUS_TYPE_ARRAY, DBUS_TYPE_VARIANT, DBUS_STRUCT_BEGIN_CHAR, DBUS_STRUCT_END_CHAR, DBUS_DICT_ENTRY_BEGIN_CHAR, DBUS_DICT_ENTRY_END_CHAR, DBUS_TYPE_UNIX_FD, 255 /* random invalid typecode */ }; static dbus_bool_t generate_typecode_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int byte_seq; int typecode_seq; int base_depth; base_depth = iter->depth; restart: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); if (!find_next_typecode (iter, data, expected_validity)) return FALSE; iter_recurse (iter); byte_seq = iter_get_sequence (iter); _dbus_assert (byte_seq < _dbus_string_get_length (data)); iter_recurse (iter); typecode_seq = iter_get_sequence (iter); iter_next (iter); _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes)); if (typecode_seq == _DBUS_N_ELEMENTS (typecodes)) { _dbus_assert (iter->depth == (base_depth + 2)); iter_set_sequence (iter, 0); /* reset typecode sequence */ iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_next (iter); /* go to the next byte_seq */ iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); goto restart; } _dbus_assert (iter->depth == (base_depth + 2)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); #if 0 printf ("Changing byte %d in message %d to %c\n", byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]); #endif _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]); *expected_validity = DBUS_VALIDITY_UNKNOWN; return TRUE; } #endif typedef struct { ChangeType type; dbus_uint32_t value; /* cast to signed for adjusts */ } UIntChange; static const UIntChange uint32_changes[] = { { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX }, { CHANGE_TYPE_ABSOLUTE, 0 }, { CHANGE_TYPE_ABSOLUTE, 1 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 } }; static dbus_bool_t generate_uint32_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int body_seq; int byte_seq; int change_seq; dbus_uint32_t v_UINT32; int byte_order; const UIntChange *change; int base_depth; /* Outer loop is each body, next loop is each change, * inner loop is each change location */ base_depth = iter->depth; next_body: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); body_seq = iter_get_sequence (iter); if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; _dbus_assert (iter->depth == (base_depth + 0)); iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */ iter_recurse (iter); next_change: _dbus_assert (iter->depth == (base_depth + 1)); change_seq = iter_get_sequence (iter); if (change_seq == _DBUS_N_ELEMENTS (uint32_changes)) { /* Reset change count */ iter_set_sequence (iter, 0); iter_unrecurse (iter); iter_next (iter); goto next_body; } _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); byte_seq = iter_get_sequence (iter); /* skip 4 bytes at a time */ iter_next (iter); iter_next (iter); iter_next (iter); iter_next (iter); iter_unrecurse (iter); _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq); if (byte_seq >= (_dbus_string_get_length (data) - 4)) { /* reset byte count */ _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); iter_set_sequence (iter, 0); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_next (iter); goto next_change; } _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4)); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL); change = &uint32_changes[change_seq]; if (change->type == CHANGE_TYPE_ADJUST) { v_UINT32 += (int) change->value; } else { v_UINT32 = change->value; } #if 0 printf ("body %d change %d pos %d ", body_seq, change_seq, byte_seq); if (change->type == CHANGE_TYPE_ADJUST) printf ("adjust by %d", (int) change->value); else printf ("set to %u", change->value); printf (" \t%u -> %u\n", _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL), v_UINT32); #endif _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order); *expected_validity = DBUS_VALIDITY_UNKNOWN; _dbus_assert (iter->depth == (base_depth + 1)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); return TRUE; } typedef struct { const char *name; DBusMessageGeneratorFunc func; } DBusMessageGenerator; static const DBusMessageGenerator generators[] = { { "trivial example of each message type", generate_trivial }, { "assorted arguments", generate_many_bodies }, { "assorted special cases", generate_special }, { "each uint32 modified", generate_uint32_changed }, { "wrong body lengths", generate_wrong_length }, { "each byte modified", generate_byte_changed }, #if 0 /* This is really expensive and doesn't add too much coverage */ { "change each typecode", generate_typecode_changed } #endif }; void _dbus_message_data_free (DBusMessageData *data) { _dbus_string_free (&data->data); } void _dbus_message_data_iter_init (DBusMessageDataIter *iter) { int i; iter->depth = 0; i = 0; while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) { iter->sequence_nos[i] = 0; ++i; } iter->count = 0; } dbus_bool_t _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter, DBusMessageData *data) { DBusMessageGeneratorFunc func; int generator; restart: generator = iter_get_sequence (iter); if (generator == _DBUS_N_ELEMENTS (generators)) return FALSE; iter_recurse (iter); if (iter_first_in_series (iter)) { printf (" testing message loading: %s ", generators[generator].name); fflush (stdout); } func = generators[generator].func; if (!_dbus_string_init (&data->data)) _dbus_assert_not_reached ("oom"); if ((*func)(iter, &data->data, &data->expected_validity)) ; else { iter_set_sequence (iter, 0); iter_unrecurse (iter); iter_next (iter); /* next generator */ _dbus_string_free (&data->data); printf ("%d test loads cumulative\n", iter->count); goto restart; } iter_unrecurse (iter); iter->count += 1; return TRUE; } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-marshal-validate-util.c0000644000175000017500000004164012602773110020767 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-validate-util.c Would be in dbus-marshal-validate.c, but only used by tests/bus * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #ifdef DBUS_ENABLE_EMBEDDED_TESTS #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "dbus-internals.h" #include "dbus-marshal-validate.h" #include "dbus-marshal-recursive.h" #include "dbus-test.h" #include typedef struct { const char *data; DBusValidity expected; } ValidityTest; static void run_validity_tests (const ValidityTest *tests, int n_tests, DBusValidity (* func) (const DBusString*,int,int)) { int i; for (i = 0; i < n_tests; i++) { DBusString str; DBusValidity v; _dbus_string_init_const (&str, tests[i].data); v = (*func) (&str, 0, _dbus_string_get_length (&str)); if (v != tests[i].expected) { _dbus_warn ("Improper validation result %d for '%s'\n", v, tests[i].data); _dbus_assert_not_reached ("test failed"); } ++i; } } static const ValidityTest signature_tests[] = { { "", DBUS_VALID }, { "i", DBUS_VALID }, { "ai", DBUS_VALID }, { "(i)", DBUS_VALID }, { "w", DBUS_INVALID_UNKNOWN_TYPECODE }, { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */ { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION }, { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))", DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION }, { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, { "a)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, { "(a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, { "a{ia}", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, { "a{}", DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS }, { "a{aii}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE }, /* { "a{i}", DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD }, */ /* { "{is}", DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY }, */ /* { "a{isi}", DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS }, */ }; dbus_bool_t _dbus_marshal_validate_test (void) { DBusString str; int i; const char *valid_paths[] = { "/", "/foo/bar", "/foo", "/foo/bar/baz" }; const char *invalid_paths[] = { "bar", "bar/baz", "/foo/bar/", "/foo/", "foo/", "boo//blah", "//", "///", "foo///blah/", "Hello World", "", " ", "foo bar" }; const char *valid_interfaces[] = { "org.freedesktop.Foo", "Bar.Baz", "Blah.Blah.Blah.Blah.Blah", "a.b", "a.b.c.d.e.f.g", "a0.b1.c2.d3.e4.f5.g6", "abc123.foo27" }; const char *invalid_interfaces[] = { ".", "", "..", ".Foo.Bar", "..Foo.Bar", "Foo.Bar.", "Foo.Bar..", "Foo", "9foo.bar.baz", "foo.bar..baz", "foo.bar...baz", "foo.bar.b..blah", ":", ":0-1", "10", ":11.34324", "0.0.0", "0..0", "foo.Bar.%", "foo.Bar!!", "!Foo.bar.bz", "foo.$.blah", "", " ", "foo bar" }; const char *valid_unique_names[] = { ":0", ":a", ":", ":.a", ":.1", ":0.1", ":000.2222", ":.blah", ":abce.freedesktop.blah" }; const char *invalid_unique_names[] = { //":-", ":!", //":0-10", ":blah.", ":blah.", ":blah..org", ":blah.org..", ":..blah.org", "", " ", "foo bar" }; const char *valid_members[] = { "Hello", "Bar", "foobar", "_foobar", "foo89" }; const char *invalid_members[] = { "9Hello", "10", "1", "foo-bar", "blah.org", ".blah", "blah.", "Hello.", "!foo", "", " ", "foo bar" }; const char *valid_signatures[] = { "", "sss", "i", "b" }; const char *invalid_signatures[] = { " ", "not a valid signature", "123", ".", "(", "a{(ii)i}" /* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */ }; /* Signature with reason */ run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests), _dbus_validate_signature_with_reason); /* Path validation */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_paths)) { _dbus_string_init_const (&str, valid_paths[i]); if (!_dbus_validate_path (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]); _dbus_assert_not_reached ("invalid path"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_paths)) { _dbus_string_init_const (&str, invalid_paths[i]); if (_dbus_validate_path (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]); _dbus_assert_not_reached ("valid path"); } ++i; } /* Interface validation */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) { _dbus_string_init_const (&str, valid_interfaces[i]); if (!_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]); _dbus_assert_not_reached ("invalid interface"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) { _dbus_string_init_const (&str, invalid_interfaces[i]); if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]); _dbus_assert_not_reached ("valid interface"); } ++i; } /* Bus name validation (check that valid interfaces are valid bus names, * and invalid interfaces are invalid services except if they start with ':') */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) { _dbus_string_init_const (&str, valid_interfaces[i]); if (!_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_interfaces[i]); _dbus_assert_not_reached ("invalid bus name"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) { if (invalid_interfaces[i][0] != ':') { _dbus_string_init_const (&str, invalid_interfaces[i]); if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_interfaces[i]); _dbus_assert_not_reached ("valid bus name"); } } ++i; } /* unique name validation */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names)) { _dbus_string_init_const (&str, valid_unique_names[i]); if (!_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_unique_names[i]); _dbus_assert_not_reached ("invalid unique name"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names)) { _dbus_string_init_const (&str, invalid_unique_names[i]); if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_unique_names[i]); _dbus_assert_not_reached ("valid unique name"); } ++i; } /* Error name validation (currently identical to interfaces) */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) { _dbus_string_init_const (&str, valid_interfaces[i]); if (!_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]); _dbus_assert_not_reached ("invalid error name"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) { if (invalid_interfaces[i][0] != ':') { _dbus_string_init_const (&str, invalid_interfaces[i]); if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]); _dbus_assert_not_reached ("valid error name"); } } ++i; } /* Member validation */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_members)) { _dbus_string_init_const (&str, valid_members[i]); if (!_dbus_validate_member (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]); _dbus_assert_not_reached ("invalid member"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_members)) { _dbus_string_init_const (&str, invalid_members[i]); if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]); _dbus_assert_not_reached ("valid member"); } ++i; } /* Signature validation */ i = 0; while (i < (int) _DBUS_N_ELEMENTS (valid_signatures)) { _dbus_string_init_const (&str, valid_signatures[i]); if (!_dbus_validate_signature (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]); _dbus_assert_not_reached ("invalid signature"); } ++i; } i = 0; while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures)) { _dbus_string_init_const (&str, invalid_signatures[i]); if (_dbus_validate_signature (&str, 0, _dbus_string_get_length (&str))) { _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]); _dbus_assert_not_reached ("valid signature"); } ++i; } /* Validate claimed length longer than real length */ _dbus_string_init_const (&str, "abc.efg"); if (_dbus_validate_bus_name (&str, 0, 8)) _dbus_assert_not_reached ("validated too-long string"); if (_dbus_validate_interface (&str, 0, 8)) _dbus_assert_not_reached ("validated too-long string"); if (_dbus_validate_error_name (&str, 0, 8)) _dbus_assert_not_reached ("validated too-long string"); _dbus_string_init_const (&str, "abc"); if (_dbus_validate_member (&str, 0, 4)) _dbus_assert_not_reached ("validated too-long string"); _dbus_string_init_const (&str, "sss"); if (_dbus_validate_signature (&str, 0, 4)) _dbus_assert_not_reached ("validated too-long signature"); /* Validate string exceeding max name length */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) if (!_dbus_string_append (&str, "abc.def")) _dbus_assert_not_reached ("no memory"); if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) _dbus_assert_not_reached ("validated overmax string"); if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str))) _dbus_assert_not_reached ("validated overmax string"); if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str))) _dbus_assert_not_reached ("validated overmax string"); /* overlong member */ _dbus_string_set_length (&str, 0); while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) if (!_dbus_string_append (&str, "abc")) _dbus_assert_not_reached ("no memory"); if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str))) _dbus_assert_not_reached ("validated overmax string"); /* overlong unique name */ _dbus_string_set_length (&str, 0); _dbus_string_append (&str, ":"); while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) if (!_dbus_string_append (&str, "abc")) _dbus_assert_not_reached ("no memory"); if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) _dbus_assert_not_reached ("validated overmax string"); _dbus_string_free (&str); /* Body validation; test basic validation of valid bodies for both endian */ { int sequence; DBusString signature; DBusString body; if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); sequence = 0; while (dbus_internal_do_not_use_generate_bodies (sequence, DBUS_LITTLE_ENDIAN, &signature, &body)) { DBusValidity validity; validity = _dbus_validate_body_with_reason (&signature, 0, DBUS_LITTLE_ENDIAN, NULL, &body, 0, _dbus_string_get_length (&body)); if (validity != DBUS_VALID) { _dbus_warn ("invalid code %d expected valid on sequence %d little endian\n", validity, sequence); _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); _dbus_assert_not_reached ("test failed"); } _dbus_string_set_length (&signature, 0); _dbus_string_set_length (&body, 0); ++sequence; } sequence = 0; while (dbus_internal_do_not_use_generate_bodies (sequence, DBUS_BIG_ENDIAN, &signature, &body)) { DBusValidity validity; validity = _dbus_validate_body_with_reason (&signature, 0, DBUS_BIG_ENDIAN, NULL, &body, 0, _dbus_string_get_length (&body)); if (validity != DBUS_VALID) { _dbus_warn ("invalid code %d expected valid on sequence %d big endian\n", validity, sequence); _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); _dbus_assert_not_reached ("test failed"); } _dbus_string_set_length (&signature, 0); _dbus_string_set_length (&body, 0); ++sequence; } _dbus_string_free (&signature); _dbus_string_free (&body); } return TRUE; } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-marshal-recursive-util.c0000644000175000017500000030060412624705346021215 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-recursive-util.c Would be in dbus-marshal-recursive.c, but only used in bus/tests * * Copyright (C) 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-marshal-recursive.h" #include "dbus-marshal-basic.h" #include "dbus-signature.h" #include "dbus-internals.h" #include static void basic_value_zero (DBusBasicValue *value) { value->u64 = 0; } static dbus_bool_t basic_value_equal (int type, DBusBasicValue *lhs, DBusBasicValue *rhs) { if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || type == DBUS_TYPE_OBJECT_PATH) { return strcmp (lhs->str, rhs->str) == 0; } else { return lhs->u64 == rhs->u64; } } static dbus_bool_t equal_values_helper (DBusTypeReader *lhs, DBusTypeReader *rhs) { int lhs_type; int rhs_type; lhs_type = _dbus_type_reader_get_current_type (lhs); rhs_type = _dbus_type_reader_get_current_type (rhs); if (lhs_type != rhs_type) return FALSE; if (lhs_type == DBUS_TYPE_INVALID) return TRUE; if (dbus_type_is_basic (lhs_type)) { DBusBasicValue lhs_value; DBusBasicValue rhs_value; basic_value_zero (&lhs_value); basic_value_zero (&rhs_value); _dbus_type_reader_read_basic (lhs, &lhs_value); _dbus_type_reader_read_basic (rhs, &rhs_value); return basic_value_equal (lhs_type, &lhs_value, &rhs_value); } else { DBusTypeReader lhs_sub; DBusTypeReader rhs_sub; _dbus_type_reader_recurse (lhs, &lhs_sub); _dbus_type_reader_recurse (rhs, &rhs_sub); return equal_values_helper (&lhs_sub, &rhs_sub); } } /** * See whether the two readers point to identical data blocks. * * @param lhs reader 1 * @param rhs reader 2 * @returns #TRUE if the data blocks have the same values */ dbus_bool_t _dbus_type_reader_equal_values (const DBusTypeReader *lhs, const DBusTypeReader *rhs) { DBusTypeReader copy_lhs = *lhs; DBusTypeReader copy_rhs = *rhs; return equal_values_helper (©_lhs, ©_rhs); } /* TESTS */ #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "dbus-test.h" #include "dbus-list.h" #include #include /* Whether to do the OOM stuff (only with other expensive tests) */ #define TEST_OOM_HANDLING 0 /* We do start offset 0 through 9, to get various alignment cases. Still this * obviously makes the test suite run 10x as slow. */ #define MAX_INITIAL_OFFSET 9 /* Largest iteration count to test copying, realignment, * etc. with. i.e. we only test this stuff with some of the smaller * data sets. */ #define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000 typedef struct { int byte_order; int initial_offset; DBusString signature; DBusString body; } DataBlock; typedef struct { int saved_sig_len; int saved_body_len; } DataBlockState; #define N_FENCE_BYTES 5 #define FENCE_BYTES_STR "abcde" #define INITIAL_PADDING_BYTE '\0' static dbus_bool_t data_block_init (DataBlock *block, int byte_order, int initial_offset) { if (!_dbus_string_init (&block->signature)) return FALSE; if (!_dbus_string_init (&block->body)) { _dbus_string_free (&block->signature); return FALSE; } if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset, INITIAL_PADDING_BYTE) || !_dbus_string_insert_bytes (&block->body, 0, initial_offset, INITIAL_PADDING_BYTE) || !_dbus_string_append (&block->signature, FENCE_BYTES_STR) || !_dbus_string_append (&block->body, FENCE_BYTES_STR)) { _dbus_string_free (&block->signature); _dbus_string_free (&block->body); return FALSE; } block->byte_order = byte_order; block->initial_offset = initial_offset; return TRUE; } static void data_block_save (DataBlock *block, DataBlockState *state) { state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES; state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES; } static void data_block_restore (DataBlock *block, DataBlockState *state) { _dbus_string_delete (&block->signature, state->saved_sig_len, _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES); _dbus_string_delete (&block->body, state->saved_body_len, _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES); } static void data_block_verify (DataBlock *block) { if (!_dbus_string_ends_with_c_str (&block->signature, FENCE_BYTES_STR)) { int offset; offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8; if (offset < 0) offset = 0; _dbus_verbose_bytes_of_string (&block->signature, offset, _dbus_string_get_length (&block->signature) - offset); _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature"); } if (!_dbus_string_ends_with_c_str (&block->body, FENCE_BYTES_STR)) { int offset; offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8; if (offset < 0) offset = 0; _dbus_verbose_bytes_of_string (&block->body, offset, _dbus_string_get_length (&block->body) - offset); _dbus_assert_not_reached ("block did not verify: bad bytes at end of body"); } _dbus_assert (_dbus_string_validate_nul (&block->signature, 0, block->initial_offset)); _dbus_assert (_dbus_string_validate_nul (&block->body, 0, block->initial_offset)); } static void data_block_free (DataBlock *block) { data_block_verify (block); _dbus_string_free (&block->signature); _dbus_string_free (&block->body); } static void data_block_reset (DataBlock *block) { data_block_verify (block); _dbus_string_delete (&block->signature, block->initial_offset, _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset); _dbus_string_delete (&block->body, block->initial_offset, _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset); data_block_verify (block); } static void data_block_init_reader_writer (DataBlock *block, DBusTypeReader *reader, DBusTypeWriter *writer) { if (reader) _dbus_type_reader_init (reader, block->byte_order, &block->signature, block->initial_offset, &block->body, block->initial_offset); if (writer) _dbus_type_writer_init (writer, block->byte_order, &block->signature, _dbus_string_get_length (&block->signature) - N_FENCE_BYTES, &block->body, _dbus_string_get_length (&block->body) - N_FENCE_BYTES); } static void real_check_expected_type (DBusTypeReader *reader, int expected, const char *funcname, int line) { int t; t = _dbus_type_reader_get_current_type (reader); if (t != expected) { _dbus_warn ("Read type %s while expecting %s at %s line %d\n", _dbus_type_to_string (t), _dbus_type_to_string (expected), funcname, line); _dbus_assert_not_reached ("read wrong type"); } } #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__) #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \ { \ _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \ _DBUS_FUNCTION_NAME, __LINE__); \ _dbus_assert_not_reached ("test failed"); \ } \ } while (0) #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \ { \ _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \ _DBUS_FUNCTION_NAME, __LINE__); \ _dbus_assert_not_reached ("test failed"); \ } \ check_expected_type (reader, DBUS_TYPE_INVALID); \ } while (0) typedef struct TestTypeNode TestTypeNode; typedef struct TestTypeNodeClass TestTypeNodeClass; typedef struct TestTypeNodeContainer TestTypeNodeContainer; typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass; struct TestTypeNode { const TestTypeNodeClass *klass; }; struct TestTypeNodeContainer { TestTypeNode base; DBusList *children; }; struct TestTypeNodeClass { int typecode; int instance_size; int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */ dbus_bool_t (* construct) (TestTypeNode *node); void (* destroy) (TestTypeNode *node); dbus_bool_t (* write_value) (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); dbus_bool_t (* read_value) (TestTypeNode *node, DBusTypeReader *reader, int seed); dbus_bool_t (* set_value) (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); dbus_bool_t (* build_signature) (TestTypeNode *node, DBusString *str); dbus_bool_t (* write_multi) (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int count); dbus_bool_t (* read_multi) (TestTypeNode *node, DBusTypeReader *reader, int seed, int count); }; struct TestTypeNodeContainerClass { TestTypeNodeClass base; }; /* FIXME this could be chilled out substantially by unifying * the basic types into basic_write_value/basic_read_value * and by merging read_value and set_value into one function * taking a flag argument. */ static dbus_bool_t int16_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t int16_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t int16_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t int16_write_multi (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int count); static dbus_bool_t int16_read_multi (TestTypeNode *node, DBusTypeReader *reader, int seed, int count); static dbus_bool_t int32_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t int32_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t int32_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t int32_write_multi (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int count); static dbus_bool_t int32_read_multi (TestTypeNode *node, DBusTypeReader *reader, int seed, int count); static dbus_bool_t int64_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t int64_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t int64_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t string_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t string_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t string_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t bool_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t bool_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t bool_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t byte_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t byte_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t byte_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t double_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t double_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t double_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t object_path_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t object_path_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t object_path_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t signature_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t signature_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t signature_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t struct_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t struct_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t struct_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t struct_build_signature (TestTypeNode *node, DBusString *str); static dbus_bool_t dict_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t dict_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t dict_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t dict_build_signature (TestTypeNode *node, DBusString *str); static dbus_bool_t array_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t array_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t array_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static dbus_bool_t array_build_signature (TestTypeNode *node, DBusString *str); static dbus_bool_t variant_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed); static dbus_bool_t variant_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed); static dbus_bool_t variant_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed); static void container_destroy (TestTypeNode *node); static const TestTypeNodeClass int16_class = { DBUS_TYPE_INT16, sizeof (TestTypeNode), 0, NULL, NULL, int16_write_value, int16_read_value, int16_set_value, NULL, int16_write_multi, int16_read_multi }; static const TestTypeNodeClass uint16_class = { DBUS_TYPE_UINT16, sizeof (TestTypeNode), 0, NULL, NULL, int16_write_value, /* recycle from int16 */ int16_read_value, /* recycle from int16 */ int16_set_value, /* recycle from int16 */ NULL, int16_write_multi, /* recycle from int16 */ int16_read_multi /* recycle from int16 */ }; static const TestTypeNodeClass int32_class = { DBUS_TYPE_INT32, sizeof (TestTypeNode), 0, NULL, NULL, int32_write_value, int32_read_value, int32_set_value, NULL, int32_write_multi, int32_read_multi }; static const TestTypeNodeClass uint32_class = { DBUS_TYPE_UINT32, sizeof (TestTypeNode), 0, NULL, NULL, int32_write_value, /* recycle from int32 */ int32_read_value, /* recycle from int32 */ int32_set_value, /* recycle from int32 */ NULL, int32_write_multi, /* recycle from int32 */ int32_read_multi /* recycle from int32 */ }; static const TestTypeNodeClass int64_class = { DBUS_TYPE_INT64, sizeof (TestTypeNode), 0, NULL, NULL, int64_write_value, int64_read_value, int64_set_value, NULL, NULL, /* FIXME */ NULL /* FIXME */ }; static const TestTypeNodeClass uint64_class = { DBUS_TYPE_UINT64, sizeof (TestTypeNode), 0, NULL, NULL, int64_write_value, /* recycle from int64 */ int64_read_value, /* recycle from int64 */ int64_set_value, /* recycle from int64 */ NULL, NULL, /* FIXME */ NULL /* FIXME */ }; static const TestTypeNodeClass string_0_class = { DBUS_TYPE_STRING, sizeof (TestTypeNode), 0, /* string length */ NULL, NULL, string_write_value, string_read_value, string_set_value, NULL, NULL, NULL }; static const TestTypeNodeClass string_1_class = { DBUS_TYPE_STRING, sizeof (TestTypeNode), 1, /* string length */ NULL, NULL, string_write_value, string_read_value, string_set_value, NULL, NULL, NULL }; /* with nul, a len 3 string should fill 4 bytes and thus is "special" */ static const TestTypeNodeClass string_3_class = { DBUS_TYPE_STRING, sizeof (TestTypeNode), 3, /* string length */ NULL, NULL, string_write_value, string_read_value, string_set_value, NULL, NULL, NULL }; /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */ static const TestTypeNodeClass string_8_class = { DBUS_TYPE_STRING, sizeof (TestTypeNode), 8, /* string length */ NULL, NULL, string_write_value, string_read_value, string_set_value, NULL, NULL, NULL }; static const TestTypeNodeClass bool_class = { DBUS_TYPE_BOOLEAN, sizeof (TestTypeNode), 0, NULL, NULL, bool_write_value, bool_read_value, bool_set_value, NULL, NULL, /* FIXME */ NULL /* FIXME */ }; static const TestTypeNodeClass byte_class = { DBUS_TYPE_BYTE, sizeof (TestTypeNode), 0, NULL, NULL, byte_write_value, byte_read_value, byte_set_value, NULL, NULL, /* FIXME */ NULL /* FIXME */ }; static const TestTypeNodeClass double_class = { DBUS_TYPE_DOUBLE, sizeof (TestTypeNode), 0, NULL, NULL, double_write_value, double_read_value, double_set_value, NULL, NULL, /* FIXME */ NULL /* FIXME */ }; static const TestTypeNodeClass object_path_class = { DBUS_TYPE_OBJECT_PATH, sizeof (TestTypeNode), 0, NULL, NULL, object_path_write_value, object_path_read_value, object_path_set_value, NULL, NULL, NULL }; static const TestTypeNodeClass signature_class = { DBUS_TYPE_SIGNATURE, sizeof (TestTypeNode), 0, NULL, NULL, signature_write_value, signature_read_value, signature_set_value, NULL, NULL, NULL }; static const TestTypeNodeClass struct_1_class = { DBUS_TYPE_STRUCT, sizeof (TestTypeNodeContainer), 1, /* number of times children appear as fields */ NULL, container_destroy, struct_write_value, struct_read_value, struct_set_value, struct_build_signature, NULL, NULL }; static const TestTypeNodeClass struct_2_class = { DBUS_TYPE_STRUCT, sizeof (TestTypeNodeContainer), 2, /* number of times children appear as fields */ NULL, container_destroy, struct_write_value, struct_read_value, struct_set_value, struct_build_signature, NULL, NULL }; static const TestTypeNodeClass dict_1_class = { DBUS_TYPE_ARRAY, /* this is correct, a dict is an array of dict entry */ sizeof (TestTypeNodeContainer), 1, /* number of entries */ NULL, container_destroy, dict_write_value, dict_read_value, dict_set_value, dict_build_signature, NULL, NULL }; static dbus_bool_t arrays_write_fixed_in_blocks = FALSE; static const TestTypeNodeClass array_0_class = { DBUS_TYPE_ARRAY, sizeof (TestTypeNodeContainer), 0, /* number of array elements */ NULL, container_destroy, array_write_value, array_read_value, array_set_value, array_build_signature, NULL, NULL }; static const TestTypeNodeClass array_1_class = { DBUS_TYPE_ARRAY, sizeof (TestTypeNodeContainer), 1, /* number of array elements */ NULL, container_destroy, array_write_value, array_read_value, array_set_value, array_build_signature, NULL, NULL }; static const TestTypeNodeClass array_2_class = { DBUS_TYPE_ARRAY, sizeof (TestTypeNodeContainer), 2, /* number of array elements */ NULL, container_destroy, array_write_value, array_read_value, array_set_value, array_build_signature, NULL, NULL }; static const TestTypeNodeClass array_9_class = { DBUS_TYPE_ARRAY, sizeof (TestTypeNodeContainer), 9, /* number of array elements */ NULL, container_destroy, array_write_value, array_read_value, array_set_value, array_build_signature, NULL, NULL }; static const TestTypeNodeClass variant_class = { DBUS_TYPE_VARIANT, sizeof (TestTypeNodeContainer), 0, NULL, container_destroy, variant_write_value, variant_read_value, variant_set_value, NULL, NULL, NULL }; static const TestTypeNodeClass* const basic_nodes[] = { &int16_class, &uint16_class, &int32_class, &uint32_class, &int64_class, &uint64_class, &bool_class, &byte_class, &double_class, &string_0_class, &string_1_class, &string_3_class, &string_8_class, &object_path_class, &signature_class }; #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes)) static const TestTypeNodeClass* const container_nodes[] = { &struct_1_class, &array_1_class, &struct_2_class, &array_0_class, &array_2_class, &variant_class, &dict_1_class /* last since we want struct and array before it */ /* array_9_class is omitted on purpose, it's too slow; * we only use it in one hardcoded test below */ }; #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes)) static TestTypeNode* node_new (const TestTypeNodeClass *klass) { TestTypeNode *node; node = dbus_malloc0 (klass->instance_size); if (node == NULL) return NULL; node->klass = klass; if (klass->construct) { if (!(* klass->construct) (node)) { dbus_free (node); return NULL; } } return node; } static void node_destroy (TestTypeNode *node) { if (node->klass->destroy) (* node->klass->destroy) (node); dbus_free (node); } static dbus_bool_t node_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { dbus_bool_t retval; retval = (* node->klass->write_value) (node, block, writer, seed); #if 0 /* Handy to see where things break, but too expensive to do all the time */ data_block_verify (block); #endif return retval; } static dbus_bool_t node_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { /* DBusTypeReader restored; */ if (!(* node->klass->read_value) (node, reader, seed)) return FALSE; return TRUE; } /* Warning: if this one fails due to OOM, it has side effects (can * modify only some of the sub-values). OK in a test suite, but we * never do this in real code. */ static dbus_bool_t node_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { if (!(* node->klass->set_value) (node, reader, realign_root, seed)) return FALSE; return TRUE; } static dbus_bool_t node_build_signature (TestTypeNode *node, DBusString *str) { if (node->klass->build_signature) return (* node->klass->build_signature) (node, str); else return _dbus_string_append_byte (str, node->klass->typecode); } static dbus_bool_t node_append_child (TestTypeNode *node, TestTypeNode *child) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer)); if (!_dbus_list_append (&container->children, child)) _dbus_assert_not_reached ("no memory"); /* we never check the return value on node_append_child anyhow - it's run from outside the malloc-failure test code */ return TRUE; } static dbus_bool_t node_write_multi (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int n_copies) { dbus_bool_t retval; _dbus_assert (node->klass->write_multi != NULL); retval = (* node->klass->write_multi) (node, block, writer, seed, n_copies); #if 0 /* Handy to see where things break, but too expensive to do all the time */ data_block_verify (block); #endif return retval; } static dbus_bool_t node_read_multi (TestTypeNode *node, DBusTypeReader *reader, int seed, int n_copies) { _dbus_assert (node->klass->read_multi != NULL); if (!(* node->klass->read_multi) (node, reader, seed, n_copies)) return FALSE; return TRUE; } static int n_iterations_completed_total = 0; static int n_iterations_completed_this_test = 0; static int n_iterations_expected_this_test = 0; typedef struct { const DBusString *signature; DataBlock *block; int type_offset; TestTypeNode **nodes; int n_nodes; } NodeIterationData; static dbus_bool_t run_test_copy (NodeIterationData *nid) { DataBlock *src; DataBlock dest; dbus_bool_t retval; DBusTypeReader reader; DBusTypeWriter writer; _dbus_verbose ("\n"); src = nid->block; retval = FALSE; if (!data_block_init (&dest, src->byte_order, src->initial_offset)) return FALSE; data_block_init_reader_writer (src, &reader, NULL); data_block_init_reader_writer (&dest, NULL, &writer); /* DBusTypeWriter assumes it's writing into an existing signature, * so doesn't add nul on its own. We have to do that. */ if (!_dbus_string_insert_byte (&dest.signature, dest.initial_offset, '\0')) goto out; if (!_dbus_type_writer_write_reader (&writer, &reader)) goto out; /* Data blocks should now be identical */ if (!_dbus_string_equal (&src->signature, &dest.signature)) { _dbus_verbose ("SOURCE\n"); _dbus_verbose_bytes_of_string (&src->signature, 0, _dbus_string_get_length (&src->signature)); _dbus_verbose ("DEST\n"); _dbus_verbose_bytes_of_string (&dest.signature, 0, _dbus_string_get_length (&dest.signature)); _dbus_assert_not_reached ("signatures did not match"); } if (!_dbus_string_equal (&src->body, &dest.body)) { _dbus_verbose ("SOURCE\n"); _dbus_verbose_bytes_of_string (&src->body, 0, _dbus_string_get_length (&src->body)); _dbus_verbose ("DEST\n"); _dbus_verbose_bytes_of_string (&dest.body, 0, _dbus_string_get_length (&dest.body)); _dbus_assert_not_reached ("bodies did not match"); } retval = TRUE; out: data_block_free (&dest); return retval; } static dbus_bool_t run_test_values_only_write (NodeIterationData *nid) { DBusTypeReader reader; DBusTypeWriter writer; int i; dbus_bool_t retval; int sig_len; _dbus_verbose ("\n"); retval = FALSE; data_block_reset (nid->block); sig_len = _dbus_string_get_length (nid->signature); _dbus_type_writer_init_values_only (&writer, nid->block->byte_order, nid->signature, 0, &nid->block->body, _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES); _dbus_type_reader_init (&reader, nid->block->byte_order, nid->signature, 0, &nid->block->body, nid->block->initial_offset); i = 0; while (i < nid->n_nodes) { if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) goto out; ++i; } /* if we wrote any typecodes then this would fail */ _dbus_assert (sig_len == _dbus_string_get_length (nid->signature)); /* But be sure we wrote out the values correctly */ i = 0; while (i < nid->n_nodes) { if (!node_read_value (nid->nodes[i], &reader, i)) goto out; if (i + 1 == nid->n_nodes) NEXT_EXPECTING_FALSE (&reader); else NEXT_EXPECTING_TRUE (&reader); ++i; } retval = TRUE; out: data_block_reset (nid->block); return retval; } /* offset the seed for setting, so we set different numbers than * we originally wrote. Don't offset by a huge number since in * some cases it's value = possibilities[seed % n_possibilities] * and we don't want to wrap around. bool_from_seed * is just seed % 2 even. */ #define SET_SEED 1 static dbus_bool_t run_test_set_values (NodeIterationData *nid) { DBusTypeReader reader; DBusTypeReader realign_root; dbus_bool_t retval; int i; _dbus_verbose ("\n"); retval = FALSE; data_block_init_reader_writer (nid->block, &reader, NULL); realign_root = reader; i = 0; while (i < nid->n_nodes) { if (!node_set_value (nid->nodes[i], &reader, &realign_root, i + SET_SEED)) goto out; if (i + 1 == nid->n_nodes) NEXT_EXPECTING_FALSE (&reader); else NEXT_EXPECTING_TRUE (&reader); ++i; } /* Check that the new values were set */ reader = realign_root; i = 0; while (i < nid->n_nodes) { if (!node_read_value (nid->nodes[i], &reader, i + SET_SEED)) goto out; if (i + 1 == nid->n_nodes) NEXT_EXPECTING_FALSE (&reader); else NEXT_EXPECTING_TRUE (&reader); ++i; } retval = TRUE; out: return retval; } static dbus_bool_t run_test_delete_values (NodeIterationData *nid) { DBusTypeReader reader; dbus_bool_t retval; int t; _dbus_verbose ("\n"); retval = FALSE; data_block_init_reader_writer (nid->block, &reader, NULL); while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) { /* Right now, deleting only works on array elements. We delete * all array elements, and then verify that there aren't any * left. */ if (t == DBUS_TYPE_ARRAY) { DBusTypeReader array; int n_elements; int elem_type; _dbus_type_reader_recurse (&reader, &array); n_elements = 0; while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) { n_elements += 1; _dbus_type_reader_next (&array); } /* reset to start of array */ _dbus_type_reader_recurse (&reader, &array); _dbus_verbose ("recursing into deletion loop reader.value_pos = %d array.value_pos = %d array.u.start_pos = %d\n", reader.value_pos, array.value_pos, array.u.array.start_pos); while ((elem_type = _dbus_type_reader_get_current_type (&array)) != DBUS_TYPE_INVALID) { /* We don't want to always delete from the same part of the array. */ static int cycle = 0; int elem; _dbus_assert (n_elements > 0); elem = cycle; if (elem == 3 || elem >= n_elements) /* end of array */ elem = n_elements - 1; _dbus_verbose ("deleting array element %d of %d type %s cycle %d reader pos %d elem pos %d\n", elem, n_elements, _dbus_type_to_string (elem_type), cycle, reader.value_pos, array.value_pos); while (elem > 0) { if (!_dbus_type_reader_next (&array)) _dbus_assert_not_reached ("should have had another element\n"); --elem; } if (!_dbus_type_reader_delete (&array, &reader)) goto out; n_elements -= 1; /* reset */ _dbus_type_reader_recurse (&reader, &array); if (cycle > 2) cycle = 0; else cycle += 1; } } _dbus_type_reader_next (&reader); } /* Check that there are no array elements left */ data_block_init_reader_writer (nid->block, &reader, NULL); while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) { _dbus_type_reader_next (&reader); } retval = TRUE; out: return retval; } static dbus_bool_t run_test_nodes_iteration (void *data) { NodeIterationData *nid = data; DBusTypeReader reader; DBusTypeWriter writer; int i; dbus_bool_t retval; /* Stuff to do: * 1. write the value * 2. strcmp-compare with the signature we built * 3. read the value * 4. type-iterate the signature and the value and see if they are the same type-wise */ retval = FALSE; data_block_init_reader_writer (nid->block, &reader, &writer); /* DBusTypeWriter assumes it's writing into an existing signature, * so doesn't add nul on its own. We have to do that. */ if (!_dbus_string_insert_byte (&nid->block->signature, nid->type_offset, '\0')) goto out; i = 0; while (i < nid->n_nodes) { if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) goto out; ++i; } if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature), &nid->block->signature, nid->type_offset)) { _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n", _dbus_string_get_const_data (nid->signature), _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0), nid->type_offset); _dbus_assert_not_reached ("wrong signature"); } i = 0; while (i < nid->n_nodes) { if (!node_read_value (nid->nodes[i], &reader, i)) goto out; if (i + 1 == nid->n_nodes) NEXT_EXPECTING_FALSE (&reader); else NEXT_EXPECTING_TRUE (&reader); ++i; } if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) { /* this set values test uses code from copy and * values_only_write so would ideally be last so you get a * simpler test case for problems with copying or values_only * writing; but it also needs an already-written DataBlock so it * has to go first. Comment it out if it breaks, and see if the * later tests also break - debug them first if so. */ if (!run_test_set_values (nid)) goto out; if (!run_test_delete_values (nid)) goto out; if (!run_test_copy (nid)) goto out; if (!run_test_values_only_write (nid)) goto out; } /* FIXME type-iterate both signature and value and compare the resulting * tree to the node tree perhaps */ retval = TRUE; out: data_block_reset (nid->block); return retval; } static void run_test_nodes_in_one_configuration (TestTypeNode **nodes, int n_nodes, const DBusString *signature, int byte_order, int initial_offset) { DataBlock block; NodeIterationData nid; if (!data_block_init (&block, byte_order, initial_offset)) _dbus_assert_not_reached ("no memory"); nid.signature = signature; nid.block = █ nid.type_offset = initial_offset; nid.nodes = nodes; nid.n_nodes = n_nodes; if (TEST_OOM_HANDLING && n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) { _dbus_test_oom_handling ("running test node", run_test_nodes_iteration, &nid); } else { if (!run_test_nodes_iteration (&nid)) _dbus_assert_not_reached ("no memory"); } data_block_free (&block); } static void run_test_nodes (TestTypeNode **nodes, int n_nodes) { int i; DBusString signature; if (!_dbus_string_init (&signature)) _dbus_assert_not_reached ("no memory"); i = 0; while (i < n_nodes) { if (! node_build_signature (nodes[i], &signature)) _dbus_assert_not_reached ("no memory"); ++i; } _dbus_verbose (">>> test nodes with signature '%s'\n", _dbus_string_get_const_data (&signature)); i = 0; while (i <= MAX_INITIAL_OFFSET) { run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, DBUS_LITTLE_ENDIAN, i); run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, DBUS_BIG_ENDIAN, i); ++i; } n_iterations_completed_this_test += 1; n_iterations_completed_total += 1; if (n_iterations_completed_this_test == n_iterations_expected_this_test) { fprintf (stderr, " 100%% %d this test (%d cumulative)\n", n_iterations_completed_this_test, n_iterations_completed_total); } /* this happens to turn out well with mod == 1 */ else if ((n_iterations_completed_this_test % (int)(n_iterations_expected_this_test / 10.0)) == 1) { fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100)); } _dbus_string_free (&signature); } #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS) static TestTypeNode* value_generator (int *ip) { int i = *ip; const TestTypeNodeClass *child_klass; const TestTypeNodeClass *container_klass; TestTypeNode *child; TestTypeNode *node; _dbus_assert (i <= N_VALUES); if (i == N_VALUES) { return NULL; } else if (i < N_BASICS) { node = node_new (basic_nodes[i]); } else { /* imagine an array: * container 0 of basic 0 * container 0 of basic 1 * container 0 of basic 2 * container 1 of basic 0 * container 1 of basic 1 * container 1 of basic 2 */ i -= N_BASICS; container_klass = container_nodes[i / N_BASICS]; child_klass = basic_nodes[i % N_BASICS]; node = node_new (container_klass); child = node_new (child_klass); node_append_child (node, child); } *ip += 1; /* increment the generator */ return node; } static void build_body (TestTypeNode **nodes, int n_nodes, int byte_order, DBusString *signature, DBusString *body) { int i; DataBlock block; DBusTypeReader reader; DBusTypeWriter writer; i = 0; while (i < n_nodes) { if (! node_build_signature (nodes[i], signature)) _dbus_assert_not_reached ("no memory"); ++i; } if (!data_block_init (&block, byte_order, 0)) _dbus_assert_not_reached ("no memory"); data_block_init_reader_writer (&block, &reader, &writer); /* DBusTypeWriter assumes it's writing into an existing signature, * so doesn't add nul on its own. We have to do that. */ if (!_dbus_string_insert_byte (&block.signature, 0, '\0')) _dbus_assert_not_reached ("no memory"); i = 0; while (i < n_nodes) { if (!node_write_value (nodes[i], &block, &writer, i)) _dbus_assert_not_reached ("no memory"); ++i; } if (!_dbus_string_copy_len (&block.body, 0, _dbus_string_get_length (&block.body) - N_FENCE_BYTES, body, 0)) _dbus_assert_not_reached ("oom"); data_block_free (&block); } dbus_bool_t dbus_internal_do_not_use_generate_bodies (int sequence, int byte_order, DBusString *signature, DBusString *body) { TestTypeNode *nodes[1]; int i; int n_nodes; nodes[0] = value_generator (&sequence); if (nodes[0] == NULL) return FALSE; n_nodes = 1; build_body (nodes, n_nodes, byte_order, signature, body); i = 0; while (i < n_nodes) { node_destroy (nodes[i]); ++i; } return TRUE; } static void make_and_run_values_inside_container (const TestTypeNodeClass *container_klass, int n_nested) { TestTypeNode *root; TestTypeNode *container; TestTypeNode *child; int i; root = node_new (container_klass); container = root; for (i = 1; i < n_nested; i++) { child = node_new (container_klass); node_append_child (container, child); container = child; } /* container should now be the most-nested container */ i = 0; while ((child = value_generator (&i))) { node_append_child (container, child); run_test_nodes (&root, 1); _dbus_list_clear (&((TestTypeNodeContainer*)container)->children); node_destroy (child); } node_destroy (root); } static void start_next_test (const char *format, int expected) { n_iterations_completed_this_test = 0; n_iterations_expected_this_test = expected; fprintf (stderr, ">>> >>> "); fprintf (stderr, format, n_iterations_expected_this_test); } static void make_and_run_test_nodes (void) { int i, j, k, m; /* We try to do this in order of "complicatedness" so that test * failures tend to show up in the simplest test case that * demonstrates the failure. There are also some tests that run * more than once for this reason, first while going through simple * cases, second while going through a broader range of complex * cases. */ /* Each basic node. The basic nodes should include: * * - each fixed-size type (in such a way that it has different values each time, * so we can tell if we mix two of them up) * - strings of various lengths * - object path * - signature */ /* Each container node. The container nodes should include: * * struct with 1 and 2 copies of the contained item * array with 0, 1, 2 copies of the contained item * variant */ /* Let a "value" be a basic node, or a container containing a single basic node. * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic) * When iterating through all values to make combinations, do the basic types * first and the containers second. */ /* Each item is shown with its number of iterations to complete so * we can keep a handle on this unit test */ /* FIXME test just an empty body, no types at all */ start_next_test ("Each value by itself %d iterations\n", N_VALUES); { TestTypeNode *node; i = 0; while ((node = value_generator (&i))) { run_test_nodes (&node, 1); node_destroy (node); } } start_next_test ("Each value by itself with arrays as blocks %d iterations\n", N_VALUES); arrays_write_fixed_in_blocks = TRUE; { TestTypeNode *node; i = 0; while ((node = value_generator (&i))) { run_test_nodes (&node, 1); node_destroy (node); } } arrays_write_fixed_in_blocks = FALSE; start_next_test ("All values in one big toplevel %d iteration\n", 1); { TestTypeNode *nodes[N_VALUES]; TestTypeNode *node; i = 0; while ((node = value_generator (&i))) { nodes[i - 1] = node; } run_test_nodes (nodes, N_VALUES); for (i = 0; i < N_VALUES; i++) node_destroy (nodes[i]); } start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n", N_VALUES * N_VALUES); { TestTypeNode *nodes[2]; i = 0; while ((nodes[0] = value_generator (&i))) { j = 0; while ((nodes[1] = value_generator (&j))) { run_test_nodes (nodes, 2); node_destroy (nodes[1]); } node_destroy (nodes[0]); } } start_next_test ("Each container containing each value %d iterations\n", N_CONTAINERS * N_VALUES); for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *container_klass = container_nodes[i]; make_and_run_values_inside_container (container_klass, 1); } start_next_test ("Each container containing each value with arrays as blocks %d iterations\n", N_CONTAINERS * N_VALUES); arrays_write_fixed_in_blocks = TRUE; for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *container_klass = container_nodes[i]; make_and_run_values_inside_container (container_klass, 1); } arrays_write_fixed_in_blocks = FALSE; start_next_test ("Each container of same container of each value %d iterations\n", N_CONTAINERS * N_VALUES); for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *container_klass = container_nodes[i]; make_and_run_values_inside_container (container_klass, 2); } start_next_test ("Each container of same container of same container of each value %d iterations\n", N_CONTAINERS * N_VALUES); for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *container_klass = container_nodes[i]; make_and_run_values_inside_container (container_klass, 3); } start_next_test ("Each value,value pair inside a struct %d iterations\n", N_VALUES * N_VALUES); { TestTypeNode *val1, *val2; TestTypeNode *node; node = node_new (&struct_1_class); i = 0; while ((val1 = value_generator (&i))) { j = 0; while ((val2 = value_generator (&j))) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; node_append_child (node, val1); node_append_child (node, val2); run_test_nodes (&node, 1); _dbus_list_clear (&container->children); node_destroy (val2); } node_destroy (val1); } node_destroy (node); } start_next_test ("All values in one big struct %d iteration\n", 1); { TestTypeNode *node; TestTypeNode *child; node = node_new (&struct_1_class); i = 0; while ((child = value_generator (&i))) node_append_child (node, child); run_test_nodes (&node, 1); node_destroy (node); } start_next_test ("Each value in a large array %d iterations\n", N_VALUES); { TestTypeNode *val; TestTypeNode *node; node = node_new (&array_9_class); i = 0; while ((val = value_generator (&i))) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; node_append_child (node, val); run_test_nodes (&node, 1); _dbus_list_clear (&container->children); node_destroy (val); } node_destroy (node); } if (_dbus_getenv ("DBUS_TEST_SLOW") == NULL || atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 1) { fprintf (stderr, "skipping remaining marshal-recursive tests, " "run with DBUS_TEST_SLOW=1 (or more) to enable\n"); goto out; } start_next_test ("Each container of each container of each value %d iterations\n", N_CONTAINERS * N_CONTAINERS * N_VALUES); for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *outer_container_klass = container_nodes[i]; TestTypeNode *outer_container = node_new (outer_container_klass); for (j = 0; j < N_CONTAINERS; j++) { TestTypeNode *child; const TestTypeNodeClass *inner_container_klass = container_nodes[j]; TestTypeNode *inner_container = node_new (inner_container_klass); node_append_child (outer_container, inner_container); m = 0; while ((child = value_generator (&m))) { node_append_child (inner_container, child); run_test_nodes (&outer_container, 1); _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); node_destroy (child); } _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); node_destroy (inner_container); } node_destroy (outer_container); } start_next_test ("Each container of each container of each container of each value %d iterations\n", N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES); for (i = 0; i < N_CONTAINERS; i++) { const TestTypeNodeClass *outer_container_klass = container_nodes[i]; TestTypeNode *outer_container = node_new (outer_container_klass); for (j = 0; j < N_CONTAINERS; j++) { const TestTypeNodeClass *inner_container_klass = container_nodes[j]; TestTypeNode *inner_container = node_new (inner_container_klass); node_append_child (outer_container, inner_container); for (k = 0; k < N_CONTAINERS; k++) { TestTypeNode *child; const TestTypeNodeClass *center_container_klass = container_nodes[k]; TestTypeNode *center_container = node_new (center_container_klass); node_append_child (inner_container, center_container); m = 0; while ((child = value_generator (&m))) { node_append_child (center_container, child); run_test_nodes (&outer_container, 1); _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children); node_destroy (child); } _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); node_destroy (center_container); } _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); node_destroy (inner_container); } node_destroy (outer_container); } /* This one takes a really long time (10 minutes on a Core2), so only enable * it if you're really sure */ if (atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 2) { fprintf (stderr, "skipping really slow marshal-recursive test, " "run with DBUS_TEST_SLOW=2 (or more) to enable\n"); goto out; } start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n", N_VALUES * N_VALUES * N_VALUES); { TestTypeNode *nodes[3]; i = 0; while ((nodes[0] = value_generator (&i))) { j = 0; while ((nodes[1] = value_generator (&j))) { k = 0; while ((nodes[2] = value_generator (&k))) { run_test_nodes (nodes, 3); node_destroy (nodes[2]); } node_destroy (nodes[1]); } node_destroy (nodes[0]); } } out: fprintf (stderr, "%d total iterations of recursive marshaling tests\n", n_iterations_completed_total); fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n", MAX_INITIAL_OFFSET); fprintf (stderr, "out of memory handling %s tested\n", TEST_OOM_HANDLING ? "was" : "was not"); } dbus_bool_t _dbus_marshal_recursive_test (void) { make_and_run_test_nodes (); return TRUE; } /* * * * Implementations of each type node class * * * */ #define MAX_MULTI_COUNT 5 #define SAMPLE_INT16 1234 #define SAMPLE_INT16_ALTERNATE 6785 static dbus_int16_t int16_from_seed (int seed) { /* Generate an integer value that's predictable from seed. We could * just use seed itself, but that would only ever touch one byte of * the int so would miss some kinds of bug. */ dbus_int16_t v; v = 42; /* just to quiet compiler afaik */ switch (seed % 5) { case 0: v = SAMPLE_INT16; break; case 1: v = SAMPLE_INT16_ALTERNATE; break; case 2: v = -1; break; case 3: v = _DBUS_INT16_MAX; break; case 4: v = 1; break; } if (seed > 1) v *= seed; /* wraps around eventually, which is fine */ return v; } static dbus_bool_t int16_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { /* also used for uint16 */ dbus_int16_t v; v = int16_from_seed (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t int16_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { /* also used for uint16 */ dbus_int16_t v; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (dbus_int16_t*) &v); _dbus_assert (v == int16_from_seed (seed)); return TRUE; } static dbus_bool_t int16_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { /* also used for uint16 */ dbus_int16_t v; v = int16_from_seed (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } static dbus_bool_t int16_write_multi (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int count) { /* also used for uint16 */ dbus_int16_t values[MAX_MULTI_COUNT]; dbus_int16_t *v_ARRAY_INT16 = values; int i; for (i = 0; i < count; ++i) values[i] = int16_from_seed (seed + i); return _dbus_type_writer_write_fixed_multi (writer, node->klass->typecode, &v_ARRAY_INT16, count); } static dbus_bool_t int16_read_multi (TestTypeNode *node, DBusTypeReader *reader, int seed, int count) { /* also used for uint16 */ dbus_int16_t *values; int n_elements; int i; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_fixed_multi (reader, &values, &n_elements); if (n_elements != count) _dbus_warn ("got %d elements expected %d\n", n_elements, count); _dbus_assert (n_elements == count); for (i = 0; i < count; i++) _dbus_assert (((dbus_int16_t)_dbus_unpack_uint16 (reader->byte_order, (const unsigned char*)values + (i * 2))) == int16_from_seed (seed + i)); return TRUE; } #define SAMPLE_INT32 12345678 #define SAMPLE_INT32_ALTERNATE 53781429 static dbus_int32_t int32_from_seed (int seed) { /* Generate an integer value that's predictable from seed. We could * just use seed itself, but that would only ever touch one byte of * the int so would miss some kinds of bug. */ dbus_int32_t v; v = 42; /* just to quiet compiler afaik */ switch (seed % 5) { case 0: v = SAMPLE_INT32; break; case 1: v = SAMPLE_INT32_ALTERNATE; break; case 2: v = -1; break; case 3: v = _DBUS_INT_MAX; break; case 4: v = 1; break; } if (seed > 1) v *= seed; /* wraps around eventually, which is fine */ return v; } static dbus_bool_t int32_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { /* also used for uint32 */ dbus_int32_t v; v = int32_from_seed (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t int32_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { /* also used for uint32 */ dbus_int32_t v; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (dbus_int32_t*) &v); _dbus_assert (v == int32_from_seed (seed)); return TRUE; } static dbus_bool_t int32_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { /* also used for uint32 */ dbus_int32_t v; v = int32_from_seed (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } static dbus_bool_t int32_write_multi (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed, int count) { /* also used for uint32 */ dbus_int32_t values[MAX_MULTI_COUNT]; dbus_int32_t *v_ARRAY_INT32 = values; int i; for (i = 0; i < count; ++i) values[i] = int32_from_seed (seed + i); return _dbus_type_writer_write_fixed_multi (writer, node->klass->typecode, &v_ARRAY_INT32, count); } static dbus_bool_t int32_read_multi (TestTypeNode *node, DBusTypeReader *reader, int seed, int count) { /* also used for uint32 */ dbus_int32_t *values; int n_elements; int i; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_fixed_multi (reader, &values, &n_elements); if (n_elements != count) _dbus_warn ("got %d elements expected %d\n", n_elements, count); _dbus_assert (n_elements == count); for (i = 0; i < count; i++) _dbus_assert (((int)_dbus_unpack_uint32 (reader->byte_order, (const unsigned char*)values + (i * 4))) == int32_from_seed (seed + i)); return TRUE; } static dbus_int64_t int64_from_seed (int seed) { dbus_int32_t v32; dbus_int64_t v; v32 = int32_from_seed (seed); v = - (dbus_int32_t) ~ v32; v |= (((dbus_int64_t)v32) << 32); return v; } static dbus_bool_t int64_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { /* also used for uint64 */ dbus_int64_t v; v = int64_from_seed (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t int64_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { /* also used for uint64 */ dbus_int64_t v; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (dbus_int64_t*) &v); _dbus_assert (v == int64_from_seed (seed)); return TRUE; } static dbus_bool_t int64_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { /* also used for uint64 */ dbus_int64_t v; v = int64_from_seed (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } #define MAX_SAMPLE_STRING_LEN 10 static void string_from_seed (char *buf, int len, int seed) { int i; unsigned char v; _dbus_assert (len < MAX_SAMPLE_STRING_LEN); /* vary the length slightly, though we also have multiple string * value types for this, varying it here tests the set_value code */ switch (seed % 3) { case 1: len += 2; break; case 2: len -= 2; break; } if (len < 0) len = 0; v = (unsigned char) ('A' + seed); i = 0; while (i < len) { if (v < 'A' || v > 'z') v = 'A'; buf[i] = v; v += 1; ++i; } buf[i] = '\0'; } static dbus_bool_t string_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { char buf[MAX_SAMPLE_STRING_LEN + 1]=""; const char *v_string = buf; string_from_seed (buf, node->klass->subclass_detail, seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v_string); } static dbus_bool_t string_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { const char *v; char buf[MAX_SAMPLE_STRING_LEN + 1]; v = buf; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (const char **) &v); string_from_seed (buf, node->klass->subclass_detail, seed); if (strcmp (buf, v) != 0) { _dbus_warn ("read string '%s' expected '%s'\n", v, buf); _dbus_assert_not_reached ("test failed"); } return TRUE; } static dbus_bool_t string_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { char buf[MAX_SAMPLE_STRING_LEN + 1]; const char *v_string = buf; string_from_seed (buf, node->klass->subclass_detail, seed); #if RECURSIVE_MARSHAL_WRITE_TRACE { const char *old; _dbus_type_reader_read_basic (reader, &old); _dbus_verbose ("SETTING new string '%s' len %d in place of '%s' len %d\n", v_string, strlen (v_string), old, strlen (old)); } #endif return _dbus_type_reader_set_basic (reader, &v_string, realign_root); } #define BOOL_FROM_SEED(seed) ((dbus_bool_t)((seed) % 2)) static dbus_bool_t bool_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { dbus_bool_t v; v = BOOL_FROM_SEED (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t bool_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { dbus_bool_t v; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (unsigned char*) &v); _dbus_assert (v == BOOL_FROM_SEED (seed)); return TRUE; } static dbus_bool_t bool_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { dbus_bool_t v; v = BOOL_FROM_SEED (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed)) static dbus_bool_t byte_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { unsigned char v; v = BYTE_FROM_SEED (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t byte_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { unsigned char v; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (unsigned char*) &v); _dbus_assert (v == BYTE_FROM_SEED (seed)); return TRUE; } static dbus_bool_t byte_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { unsigned char v; v = BYTE_FROM_SEED (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } static double double_from_seed (int seed) { return SAMPLE_INT32 * (double) seed + 0.3; } static dbus_bool_t double_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { double v; v = double_from_seed (seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v); } static dbus_bool_t double_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { double v; double expected; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (double*) &v); expected = double_from_seed (seed); if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected)) { #ifdef DBUS_INT64_PRINTF_MODIFIER _dbus_warn ("Expected double %g got %g\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x vs.\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x)\n", expected, v, *(dbus_uint64_t*)(char*)&expected, *(dbus_uint64_t*)(char*)&v); #endif _dbus_assert_not_reached ("test failed"); } return TRUE; } static dbus_bool_t double_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { double v; v = double_from_seed (seed); return _dbus_type_reader_set_basic (reader, &v, realign_root); } #define MAX_SAMPLE_OBJECT_PATH_LEN 10 static void object_path_from_seed (char *buf, int seed) { int i; unsigned char v; int len; len = seed % 9; _dbus_assert (len < MAX_SAMPLE_OBJECT_PATH_LEN); v = (unsigned char) ('A' + seed); if (len < 2) { buf[0] = '/'; i = 1; } else { i = 0; while (i + 1 < len) { if (v < 'A' || v > 'z') v = 'A'; buf[i] = '/'; ++i; buf[i] = v; ++i; v += 1; } } buf[i] = '\0'; } static dbus_bool_t object_path_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; const char *v_string = buf; object_path_from_seed (buf, seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v_string); } static dbus_bool_t object_path_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { const char *v; char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (const char **) &v); object_path_from_seed (buf, seed); if (strcmp (buf, v) != 0) { _dbus_warn ("read object path '%s' expected '%s'\n", v, buf); _dbus_assert_not_reached ("test failed"); } return TRUE; } static dbus_bool_t object_path_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; const char *v_string = buf; object_path_from_seed (buf, seed); return _dbus_type_reader_set_basic (reader, &v_string, realign_root); } #define MAX_SAMPLE_SIGNATURE_LEN 10 static void signature_from_seed (char *buf, int seed) { /* try to avoid ascending, descending, or alternating length to help find bugs */ const char *sample_signatures[] = { "asax", "", "asau(xxxx)", "x", "ai", "a(ii)" }; strcpy (buf, sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)]); } static dbus_bool_t signature_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; const char *v_string = buf; signature_from_seed (buf, seed); return _dbus_type_writer_write_basic (writer, node->klass->typecode, &v_string); } static dbus_bool_t signature_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { const char *v; char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; check_expected_type (reader, node->klass->typecode); _dbus_type_reader_read_basic (reader, (const char **) &v); signature_from_seed (buf, seed); if (strcmp (buf, v) != 0) { _dbus_warn ("read signature value '%s' expected '%s'\n", v, buf); _dbus_assert_not_reached ("test failed"); } return TRUE; } static dbus_bool_t signature_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; const char *v_string = buf; signature_from_seed (buf, seed); return _dbus_type_reader_set_basic (reader, &v_string, realign_root); } static dbus_bool_t struct_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DataBlockState saved; DBusTypeWriter sub; int i; int n_copies; n_copies = node->klass->subclass_detail; _dbus_assert (container->children != NULL); data_block_save (block, &saved); if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, NULL, 0, &sub)) return FALSE; i = 0; while (i < n_copies) { DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); if (!node_write_value (child, block, &sub, seed + i)) { data_block_restore (block, &saved); return FALSE; } link = next; } ++i; } if (!_dbus_type_writer_unrecurse (writer, &sub)) { data_block_restore (block, &saved); return FALSE; } return TRUE; } static dbus_bool_t struct_read_or_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DBusTypeReader sub; int i; int n_copies; n_copies = node->klass->subclass_detail; check_expected_type (reader, DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (reader, &sub); i = 0; while (i < n_copies) { DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); if (realign_root == NULL) { if (!node_read_value (child, &sub, seed + i)) return FALSE; } else { if (!node_set_value (child, &sub, realign_root, seed + i)) return FALSE; } if (i == (n_copies - 1) && next == NULL) NEXT_EXPECTING_FALSE (&sub); else NEXT_EXPECTING_TRUE (&sub); link = next; } ++i; } return TRUE; } static dbus_bool_t struct_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { return struct_read_or_set_value (node, reader, NULL, seed); } static dbus_bool_t struct_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { return struct_read_or_set_value (node, reader, realign_root, seed); } static dbus_bool_t struct_build_signature (TestTypeNode *node, DBusString *str) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; int i; int orig_len; int n_copies; n_copies = node->klass->subclass_detail; orig_len = _dbus_string_get_length (str); if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR)) goto oom; i = 0; while (i < n_copies) { DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); if (!node_build_signature (child, str)) goto oom; link = next; } ++i; } if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR)) goto oom; return TRUE; oom: _dbus_string_set_length (str, orig_len); return FALSE; } static dbus_bool_t array_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DataBlockState saved; DBusTypeWriter sub; DBusString element_signature; int i; int n_copies; int element_type; TestTypeNode *child; n_copies = node->klass->subclass_detail; _dbus_assert (container->children != NULL); data_block_save (block, &saved); if (!_dbus_string_init (&element_signature)) return FALSE; child = _dbus_list_get_first (&container->children); if (!node_build_signature (child, &element_signature)) goto oom; element_type = _dbus_first_type_in_signature (&element_signature, 0); if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, &element_signature, 0, &sub)) goto oom; if (arrays_write_fixed_in_blocks && dbus_type_is_fixed (element_type) && child->klass->write_multi) { if (!node_write_multi (child, block, &sub, seed, n_copies)) goto oom; } else { i = 0; while (i < n_copies) { DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); if (!node_write_value (child, block, &sub, seed + i)) goto oom; link = next; } ++i; } } if (!_dbus_type_writer_unrecurse (writer, &sub)) goto oom; _dbus_string_free (&element_signature); return TRUE; oom: data_block_restore (block, &saved); _dbus_string_free (&element_signature); return FALSE; } static dbus_bool_t array_read_or_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DBusTypeReader sub; int i; int n_copies; TestTypeNode *child; n_copies = node->klass->subclass_detail; check_expected_type (reader, DBUS_TYPE_ARRAY); child = _dbus_list_get_first (&container->children); if (n_copies > 0) { _dbus_type_reader_recurse (reader, &sub); if (realign_root == NULL && arrays_write_fixed_in_blocks && dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && child->klass->read_multi) { if (!node_read_multi (child, &sub, seed, n_copies)) return FALSE; } else { i = 0; while (i < n_copies) { DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); _dbus_assert (child->klass->typecode == _dbus_type_reader_get_element_type (reader)); if (realign_root == NULL) { if (!node_read_value (child, &sub, seed + i)) return FALSE; } else { if (!node_set_value (child, &sub, realign_root, seed + i)) return FALSE; } if (i == (n_copies - 1) && next == NULL) NEXT_EXPECTING_FALSE (&sub); else NEXT_EXPECTING_TRUE (&sub); link = next; } ++i; } } } return TRUE; } static dbus_bool_t array_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { return array_read_or_set_value (node, reader, NULL, seed); } static dbus_bool_t array_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { return array_read_or_set_value (node, reader, realign_root, seed); } static dbus_bool_t array_build_signature (TestTypeNode *node, DBusString *str) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; int orig_len; orig_len = _dbus_string_get_length (str); if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) goto oom; if (!node_build_signature (_dbus_list_get_first (&container->children), str)) goto oom; return TRUE; oom: _dbus_string_set_length (str, orig_len); return FALSE; } /* 10 is random just to add another seed that we use in the suite */ #define VARIANT_SEED 10 static dbus_bool_t variant_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DataBlockState saved; DBusTypeWriter sub; DBusString content_signature; TestTypeNode *child; _dbus_assert (container->children != NULL); _dbus_assert (_dbus_list_length_is_one (&container->children)); child = _dbus_list_get_first (&container->children); data_block_save (block, &saved); if (!_dbus_string_init (&content_signature)) return FALSE; if (!node_build_signature (child, &content_signature)) goto oom; if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT, &content_signature, 0, &sub)) goto oom; if (!node_write_value (child, block, &sub, seed + VARIANT_SEED)) goto oom; if (!_dbus_type_writer_unrecurse (writer, &sub)) goto oom; _dbus_string_free (&content_signature); return TRUE; oom: data_block_restore (block, &saved); _dbus_string_free (&content_signature); return FALSE; } static dbus_bool_t variant_read_or_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DBusTypeReader sub; TestTypeNode *child; _dbus_assert (container->children != NULL); _dbus_assert (_dbus_list_length_is_one (&container->children)); child = _dbus_list_get_first (&container->children); check_expected_type (reader, DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (reader, &sub); if (realign_root == NULL) { if (!node_read_value (child, &sub, seed + VARIANT_SEED)) return FALSE; } else { if (!node_set_value (child, &sub, realign_root, seed + VARIANT_SEED)) return FALSE; } NEXT_EXPECTING_FALSE (&sub); return TRUE; } static dbus_bool_t variant_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { return variant_read_or_set_value (node, reader, NULL, seed); } static dbus_bool_t variant_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { return variant_read_or_set_value (node, reader, realign_root, seed); } static dbus_bool_t dict_write_value (TestTypeNode *node, DataBlock *block, DBusTypeWriter *writer, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DataBlockState saved; DBusTypeWriter sub; DBusString entry_value_signature; DBusString dict_entry_signature; int i; int n_entries; TestTypeNode *child; n_entries = node->klass->subclass_detail; _dbus_assert (container->children != NULL); data_block_save (block, &saved); if (!_dbus_string_init (&entry_value_signature)) return FALSE; if (!_dbus_string_init (&dict_entry_signature)) { _dbus_string_free (&entry_value_signature); return FALSE; } child = _dbus_list_get_first (&container->children); if (!node_build_signature (child, &entry_value_signature)) goto oom; if (!_dbus_string_append (&dict_entry_signature, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING)) goto oom; if (!_dbus_string_copy (&entry_value_signature, 0, &dict_entry_signature, _dbus_string_get_length (&dict_entry_signature))) goto oom; if (!_dbus_string_append_byte (&dict_entry_signature, DBUS_DICT_ENTRY_END_CHAR)) goto oom; if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, &dict_entry_signature, 0, &sub)) goto oom; i = 0; while (i < n_entries) { DBusTypeWriter entry_sub; dbus_int32_t key; if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_DICT_ENTRY, NULL, 0, &entry_sub)) goto oom; key = int32_from_seed (seed + i); if (!_dbus_type_writer_write_basic (&entry_sub, DBUS_TYPE_INT32, &key)) goto oom; if (!node_write_value (child, block, &entry_sub, seed + i)) goto oom; if (!_dbus_type_writer_unrecurse (&sub, &entry_sub)) goto oom; ++i; } if (!_dbus_type_writer_unrecurse (writer, &sub)) goto oom; _dbus_string_free (&entry_value_signature); _dbus_string_free (&dict_entry_signature); return TRUE; oom: data_block_restore (block, &saved); _dbus_string_free (&entry_value_signature); _dbus_string_free (&dict_entry_signature); return FALSE; } static dbus_bool_t dict_read_or_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DBusTypeReader sub; int i; int n_entries; TestTypeNode *child; n_entries = node->klass->subclass_detail; check_expected_type (reader, DBUS_TYPE_ARRAY); child = _dbus_list_get_first (&container->children); if (n_entries > 0) { _dbus_type_reader_recurse (reader, &sub); check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY); i = 0; while (i < n_entries) { DBusTypeReader entry_sub; check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY); _dbus_type_reader_recurse (&sub, &entry_sub); if (realign_root == NULL) { dbus_int32_t v; check_expected_type (&entry_sub, DBUS_TYPE_INT32); _dbus_type_reader_read_basic (&entry_sub, (dbus_int32_t*) &v); _dbus_assert (v == int32_from_seed (seed + i)); NEXT_EXPECTING_TRUE (&entry_sub); if (!node_read_value (child, &entry_sub, seed + i)) return FALSE; NEXT_EXPECTING_FALSE (&entry_sub); } else { dbus_int32_t v; v = int32_from_seed (seed + i); if (!_dbus_type_reader_set_basic (&entry_sub, &v, realign_root)) return FALSE; NEXT_EXPECTING_TRUE (&entry_sub); if (!node_set_value (child, &entry_sub, realign_root, seed + i)) return FALSE; NEXT_EXPECTING_FALSE (&entry_sub); } if (i == (n_entries - 1)) NEXT_EXPECTING_FALSE (&sub); else NEXT_EXPECTING_TRUE (&sub); ++i; } } return TRUE; } static dbus_bool_t dict_read_value (TestTypeNode *node, DBusTypeReader *reader, int seed) { return dict_read_or_set_value (node, reader, NULL, seed); } static dbus_bool_t dict_set_value (TestTypeNode *node, DBusTypeReader *reader, DBusTypeReader *realign_root, int seed) { return dict_read_or_set_value (node, reader, realign_root, seed); } static dbus_bool_t dict_build_signature (TestTypeNode *node, DBusString *str) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; int orig_len; orig_len = _dbus_string_get_length (str); if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) goto oom; if (!_dbus_string_append (str, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING)) goto oom; if (!node_build_signature (_dbus_list_get_first (&container->children), str)) goto oom; if (!_dbus_string_append_byte (str, DBUS_DICT_ENTRY_END_CHAR)) goto oom; return TRUE; oom: _dbus_string_set_length (str, orig_len); return FALSE; } static void container_destroy (TestTypeNode *node) { TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; DBusList *link; link = _dbus_list_get_first_link (&container->children); while (link != NULL) { TestTypeNode *child = link->data; DBusList *next = _dbus_list_get_next_link (&container->children, link); node_destroy (child); _dbus_list_free_link (link); link = next; } } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-marshal-byteswap-util.c0000644000175000017500000000663612602773110021042 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-byteswap-util.c Would be in dbus-marshal-byteswap.c but tests/bus only * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-marshal-byteswap.h" #include "dbus-test.h" #include static void do_byteswap_test (int byte_order) { int sequence; DBusString signature; DBusString body; int opposite_order; if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); opposite_order = byte_order == DBUS_LITTLE_ENDIAN ? DBUS_BIG_ENDIAN : DBUS_LITTLE_ENDIAN; sequence = 0; while (dbus_internal_do_not_use_generate_bodies (sequence, byte_order, &signature, &body)) { DBusString copy; DBusTypeReader body_reader; DBusTypeReader copy_reader; if (!_dbus_string_init (©)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_copy (&body, 0, ©, 0)) _dbus_assert_not_reached ("oom"); _dbus_marshal_byteswap (&signature, 0, byte_order, opposite_order, ©, 0); _dbus_type_reader_init (&body_reader, byte_order, &signature, 0, &body, 0); _dbus_type_reader_init (©_reader, opposite_order, &signature, 0, ©, 0); if (!_dbus_type_reader_equal_values (&body_reader, ©_reader)) { _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); _dbus_verbose_bytes_of_string (©, 0, _dbus_string_get_length (©)); _dbus_warn ("Byte-swapped data did not have same values as original data\n"); _dbus_assert_not_reached ("test failed"); } _dbus_string_free (©); _dbus_string_set_length (&signature, 0); _dbus_string_set_length (&body, 0); ++sequence; } _dbus_string_free (&signature); _dbus_string_free (&body); printf (" %d blocks swapped from order '%c' to '%c'\n", sequence, byte_order, opposite_order); } dbus_bool_t _dbus_marshal_byteswap_test (void) { do_byteswap_test (DBUS_LITTLE_ENDIAN); do_byteswap_test (DBUS_BIG_ENDIAN); return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-mainloop.h0000644000175000017500000000530312602773110016415 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-mainloop.h Main loop utility * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MAINLOOP_H #define DBUS_MAINLOOP_H #ifndef DOXYGEN_SHOULD_SKIP_THIS #include typedef struct DBusLoop DBusLoop; typedef dbus_bool_t (* DBusWatchFunction) (DBusWatch *watch, unsigned int condition, void *data); DBusLoop* _dbus_loop_new (void); DBusLoop* _dbus_loop_ref (DBusLoop *loop); void _dbus_loop_unref (DBusLoop *loop); dbus_bool_t _dbus_loop_add_watch (DBusLoop *loop, DBusWatch *watch); void _dbus_loop_remove_watch (DBusLoop *loop, DBusWatch *watch); void _dbus_loop_toggle_watch (DBusLoop *loop, DBusWatch *watch); dbus_bool_t _dbus_loop_add_timeout (DBusLoop *loop, DBusTimeout *timeout); void _dbus_loop_remove_timeout (DBusLoop *loop, DBusTimeout *timeout); dbus_bool_t _dbus_loop_queue_dispatch (DBusLoop *loop, DBusConnection *connection); void _dbus_loop_run (DBusLoop *loop); void _dbus_loop_quit (DBusLoop *loop); dbus_bool_t _dbus_loop_iterate (DBusLoop *loop, dbus_bool_t block); dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop); int _dbus_get_oom_wait (void); void _dbus_wait_for_memory (void); #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* DBUS_MAINLOOP_H */ dbus-1.10.6/dbus/dbus-mainloop.c0000644000175000017500000005603312602773110016416 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-mainloop.c Main loop utility * * Copyright © 2003, 2004 Red Hat, Inc. * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-mainloop.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS #include #include #include #include #define MAINLOOP_SPEW 0 struct DBusLoop { int refcount; /** DBusPollable => dbus_malloc'd DBusList ** of references to DBusWatch */ DBusHashTable *watches; DBusSocketSet *socket_set; DBusList *timeouts; int callback_list_serial; int watch_count; int timeout_count; int depth; /**< number of recursive runs */ DBusList *need_dispatch; /** TRUE if we will skip a watch next time because it was OOM; becomes * FALSE between polling, and dealing with the results of the poll */ unsigned oom_watch_pending : 1; }; typedef struct { DBusTimeout *timeout; long last_tv_sec; long last_tv_usec; } TimeoutCallback; #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) static TimeoutCallback* timeout_callback_new (DBusTimeout *timeout) { TimeoutCallback *cb; cb = dbus_new (TimeoutCallback, 1); if (cb == NULL) return NULL; cb->timeout = timeout; _dbus_get_monotonic_time (&cb->last_tv_sec, &cb->last_tv_usec); return cb; } static void timeout_callback_free (TimeoutCallback *cb) { dbus_free (cb); } static void free_watch_table_entry (void *data) { DBusList **watches = data; DBusWatch *watch; /* DBusHashTable sometimes calls free_function(NULL) even if you never * have NULL as a value */ if (watches == NULL) return; for (watch = _dbus_list_pop_first (watches); watch != NULL; watch = _dbus_list_pop_first (watches)) { _dbus_watch_unref (watch); } _dbus_assert (*watches == NULL); dbus_free (watches); } DBusLoop* _dbus_loop_new (void) { DBusLoop *loop; loop = dbus_new0 (DBusLoop, 1); if (loop == NULL) return NULL; loop->watches = _dbus_hash_table_new (DBUS_HASH_POLLABLE, NULL, free_watch_table_entry); loop->socket_set = _dbus_socket_set_new (0); if (loop->watches == NULL || loop->socket_set == NULL) { if (loop->watches != NULL) _dbus_hash_table_unref (loop->watches); if (loop->socket_set != NULL) _dbus_socket_set_free (loop->socket_set); dbus_free (loop); return NULL; } loop->refcount = 1; return loop; } DBusLoop * _dbus_loop_ref (DBusLoop *loop) { _dbus_assert (loop != NULL); _dbus_assert (loop->refcount > 0); loop->refcount += 1; return loop; } void _dbus_loop_unref (DBusLoop *loop) { _dbus_assert (loop != NULL); _dbus_assert (loop->refcount > 0); loop->refcount -= 1; if (loop->refcount == 0) { while (loop->need_dispatch) { DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); dbus_connection_unref (connection); } _dbus_hash_table_unref (loop->watches); _dbus_socket_set_free (loop->socket_set); dbus_free (loop); } } static DBusList ** ensure_watch_table_entry (DBusLoop *loop, DBusPollable fd) { DBusList **watches; watches = _dbus_hash_table_lookup_pollable (loop->watches, fd); if (watches == NULL) { watches = dbus_new0 (DBusList *, 1); if (watches == NULL) return watches; if (!_dbus_hash_table_insert_pollable (loop->watches, fd, watches)) { dbus_free (watches); watches = NULL; } } return watches; } static void cull_watches_for_invalid_fd (DBusLoop *loop, DBusPollable fd) { DBusList *link; DBusList **watches; _dbus_warn ("invalid request, socket fd %" DBUS_POLLABLE_FORMAT " not open\n", _dbus_pollable_printable (fd)); watches = _dbus_hash_table_lookup_pollable (loop->watches, fd); if (watches != NULL) { for (link = _dbus_list_get_first_link (watches); link != NULL; link = _dbus_list_get_next_link (watches, link)) _dbus_watch_invalidate (link->data); } _dbus_hash_table_remove_pollable (loop->watches, fd); } static dbus_bool_t gc_watch_table_entry (DBusLoop *loop, DBusList **watches, DBusPollable fd) { /* If watches is already NULL we have nothing to do */ if (watches == NULL) return FALSE; /* We can't GC hash table entries if they're non-empty lists */ if (*watches != NULL) return FALSE; _dbus_hash_table_remove_pollable (loop->watches, fd); return TRUE; } static void refresh_watches_for_fd (DBusLoop *loop, DBusList **watches, DBusPollable fd) { DBusList *link; unsigned int flags = 0; dbus_bool_t interested = FALSE; _dbus_assert (_dbus_pollable_is_valid (fd)); if (watches == NULL) watches = _dbus_hash_table_lookup_pollable (loop->watches, fd); /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep * it until there are none left */ _dbus_assert (watches != NULL); for (link = _dbus_list_get_first_link (watches); link != NULL; link = _dbus_list_get_next_link (watches, link)) { if (dbus_watch_get_enabled (link->data) && !_dbus_watch_get_oom_last_time (link->data)) { flags |= dbus_watch_get_flags (link->data); interested = TRUE; } } if (interested) _dbus_socket_set_enable (loop->socket_set, fd, flags); else _dbus_socket_set_disable (loop->socket_set, fd); } dbus_bool_t _dbus_loop_add_watch (DBusLoop *loop, DBusWatch *watch) { DBusPollable fd; DBusList **watches; fd = _dbus_watch_get_pollable (watch); _dbus_assert (_dbus_pollable_is_valid (fd)); watches = ensure_watch_table_entry (loop, fd); if (watches == NULL) return FALSE; if (!_dbus_list_append (watches, _dbus_watch_ref (watch))) { _dbus_watch_unref (watch); gc_watch_table_entry (loop, watches, fd); return FALSE; } if (_dbus_list_length_is_one (watches)) { if (!_dbus_socket_set_add (loop->socket_set, fd, dbus_watch_get_flags (watch), dbus_watch_get_enabled (watch))) { _dbus_hash_table_remove_pollable (loop->watches, fd); return FALSE; } } else { /* we're modifying, not adding, which can't fail with OOM */ refresh_watches_for_fd (loop, watches, fd); } loop->callback_list_serial += 1; loop->watch_count += 1; return TRUE; } void _dbus_loop_toggle_watch (DBusLoop *loop, DBusWatch *watch) { refresh_watches_for_fd (loop, NULL, _dbus_watch_get_pollable (watch)); } void _dbus_loop_remove_watch (DBusLoop *loop, DBusWatch *watch) { DBusList **watches; DBusList *link; DBusPollable fd; /* This relies on people removing watches before they invalidate them, * which has been safe since fd.o #33336 was fixed. Assert about it * so we don't regress. */ fd = _dbus_watch_get_pollable (watch); _dbus_assert (_dbus_pollable_is_valid (fd)); watches = _dbus_hash_table_lookup_pollable (loop->watches, fd); if (watches != NULL) { link = _dbus_list_get_first_link (watches); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (watches, link); DBusWatch *this = link->data; if (this == watch) { _dbus_list_remove_link (watches, link); loop->callback_list_serial += 1; loop->watch_count -= 1; _dbus_watch_unref (this); /* if that was the last watch for that fd, drop the hash table * entry, and stop reserving space for it in the socket set */ if (gc_watch_table_entry (loop, watches, fd)) { _dbus_socket_set_remove (loop->socket_set, fd); } return; } link = next; } } _dbus_warn ("could not find watch %p to remove\n", watch); } dbus_bool_t _dbus_loop_add_timeout (DBusLoop *loop, DBusTimeout *timeout) { TimeoutCallback *tcb; tcb = timeout_callback_new (timeout); if (tcb == NULL) return FALSE; if (_dbus_list_append (&loop->timeouts, tcb)) { loop->callback_list_serial += 1; loop->timeout_count += 1; } else { timeout_callback_free (tcb); return FALSE; } return TRUE; } void _dbus_loop_remove_timeout (DBusLoop *loop, DBusTimeout *timeout) { DBusList *link; link = _dbus_list_get_first_link (&loop->timeouts); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); TimeoutCallback *this = link->data; if (this->timeout == timeout) { _dbus_list_remove_link (&loop->timeouts, link); loop->callback_list_serial += 1; loop->timeout_count -= 1; timeout_callback_free (this); return; } link = next; } _dbus_warn ("could not find timeout %p to remove\n", timeout); } /* Convolutions from GLib, there really must be a better way * to do this. */ static dbus_bool_t check_timeout (long tv_sec, long tv_usec, TimeoutCallback *tcb, int *timeout) { long sec_remaining; long msec_remaining; long expiration_tv_sec; long expiration_tv_usec; long interval_seconds; long interval_milliseconds; int interval; /* I'm pretty sure this function could suck (a lot) less */ interval = dbus_timeout_get_interval (tcb->timeout); interval_seconds = interval / 1000L; interval_milliseconds = interval % 1000L; expiration_tv_sec = tcb->last_tv_sec + interval_seconds; expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000; if (expiration_tv_usec >= 1000000) { expiration_tv_usec -= 1000000; expiration_tv_sec += 1; } sec_remaining = expiration_tv_sec - tv_sec; msec_remaining = (expiration_tv_usec - tv_usec) / 1000L; #if MAINLOOP_SPEW _dbus_verbose ("Interval is %ld seconds %ld msecs\n", interval_seconds, interval_milliseconds); _dbus_verbose ("Now is %lu seconds %lu usecs\n", tv_sec, tv_usec); _dbus_verbose ("Last is %lu seconds %lu usecs\n", tcb->last_tv_sec, tcb->last_tv_usec); _dbus_verbose ("Exp is %lu seconds %lu usecs\n", expiration_tv_sec, expiration_tv_usec); _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n", sec_remaining, msec_remaining); #endif /* We do the following in a rather convoluted fashion to deal with * the fact that we don't have an integral type big enough to hold * the difference of two timevals in milliseconds. */ if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0)) { *timeout = 0; } else { if (msec_remaining < 0) { msec_remaining += 1000; sec_remaining -= 1; } if (sec_remaining > (_DBUS_INT_MAX / 1000) || msec_remaining > _DBUS_INT_MAX) *timeout = _DBUS_INT_MAX; else *timeout = sec_remaining * 1000 + msec_remaining; } if (*timeout > interval) { /* This indicates that the system clock probably moved backward */ _dbus_verbose ("System clock set backward! Resetting timeout.\n"); tcb->last_tv_sec = tv_sec; tcb->last_tv_usec = tv_usec; *timeout = interval; } #if MAINLOOP_SPEW _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout); #endif return *timeout == 0; } dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop) { #if MAINLOOP_SPEW _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch)); #endif if (loop->need_dispatch == NULL) return FALSE; next: while (loop->need_dispatch != NULL) { DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); while (TRUE) { DBusDispatchStatus status; status = dbus_connection_dispatch (connection); if (status == DBUS_DISPATCH_COMPLETE) { dbus_connection_unref (connection); goto next; } else { if (status == DBUS_DISPATCH_NEED_MEMORY) _dbus_wait_for_memory (); } } } return TRUE; } dbus_bool_t _dbus_loop_queue_dispatch (DBusLoop *loop, DBusConnection *connection) { if (_dbus_list_append (&loop->need_dispatch, connection)) { dbus_connection_ref (connection); return TRUE; } else return FALSE; } /* Returns TRUE if we invoked any timeouts or have ready file * descriptors, which is just used in test code as a debug hack */ dbus_bool_t _dbus_loop_iterate (DBusLoop *loop, dbus_bool_t block) { #define N_STACK_DESCRIPTORS 64 dbus_bool_t retval; DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS]; int i; DBusList *link; int n_ready; int initial_serial; long timeout; int orig_depth; retval = FALSE; orig_depth = loop->depth; #if MAINLOOP_SPEW _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n", block, loop->depth, loop->timeout_count, loop->watch_count); #endif if (_dbus_hash_table_get_n_entries (loop->watches) == 0 && loop->timeouts == NULL) goto next_iteration; timeout = -1; if (loop->timeout_count > 0) { long tv_sec; long tv_usec; _dbus_get_monotonic_time (&tv_sec, &tv_usec); link = _dbus_list_get_first_link (&loop->timeouts); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); TimeoutCallback *tcb = link->data; if (dbus_timeout_get_enabled (tcb->timeout)) { int msecs_remaining; check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); if (timeout < 0) timeout = msecs_remaining; else timeout = MIN (msecs_remaining, timeout); #if MAINLOOP_SPEW _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n", msecs_remaining, timeout); #endif _dbus_assert (timeout >= 0); if (timeout == 0) break; /* it's not going to get shorter... */ } #if MAINLOOP_SPEW else { _dbus_verbose (" skipping disabled timeout\n"); } #endif link = next; } } /* Never block if we have stuff to dispatch */ if (!block || loop->need_dispatch != NULL) { timeout = 0; #if MAINLOOP_SPEW _dbus_verbose (" timeout is 0 as we aren't blocking\n"); #endif } /* if a watch was OOM last time, don't wait longer than the OOM * wait to re-enable it */ if (loop->oom_watch_pending) timeout = MIN (timeout, _dbus_get_oom_wait ()); #if MAINLOOP_SPEW _dbus_verbose (" polling on %d descriptors timeout %ld\n", _DBUS_N_ELEMENTS (ready_fds), timeout); #endif n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds, _DBUS_N_ELEMENTS (ready_fds), timeout); /* re-enable any watches we skipped this time */ if (loop->oom_watch_pending) { DBusHashIter hash_iter; loop->oom_watch_pending = FALSE; _dbus_hash_iter_init (loop->watches, &hash_iter); while (_dbus_hash_iter_next (&hash_iter)) { DBusList **watches; DBusPollable fd; dbus_bool_t changed; changed = FALSE; fd = _dbus_hash_iter_get_pollable_key (&hash_iter); watches = _dbus_hash_iter_get_value (&hash_iter); for (link = _dbus_list_get_first_link (watches); link != NULL; link = _dbus_list_get_next_link (watches, link)) { DBusWatch *watch = link->data; if (_dbus_watch_get_oom_last_time (watch)) { _dbus_watch_set_oom_last_time (watch, FALSE); changed = TRUE; } } if (changed) refresh_watches_for_fd (loop, watches, fd); } retval = TRUE; /* return TRUE here to keep the loop going, * since we don't know the watch was inactive */ } initial_serial = loop->callback_list_serial; if (loop->timeout_count > 0) { long tv_sec; long tv_usec; _dbus_get_monotonic_time (&tv_sec, &tv_usec); /* It'd be nice to avoid this O(n) thingy here */ link = _dbus_list_get_first_link (&loop->timeouts); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); TimeoutCallback *tcb = link->data; if (initial_serial != loop->callback_list_serial) goto next_iteration; if (loop->depth != orig_depth) goto next_iteration; if (dbus_timeout_get_enabled (tcb->timeout)) { int msecs_remaining; if (check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining)) { /* Save last callback time and fire this timeout */ tcb->last_tv_sec = tv_sec; tcb->last_tv_usec = tv_usec; #if MAINLOOP_SPEW _dbus_verbose (" invoking timeout\n"); #endif /* can theoretically return FALSE on OOM, but we just * let it fire again later - in practice that's what * every wrapper callback in dbus-daemon used to do */ dbus_timeout_handle (tcb->timeout); retval = TRUE; } else { #if MAINLOOP_SPEW _dbus_verbose (" timeout has not expired\n"); #endif } } #if MAINLOOP_SPEW else { _dbus_verbose (" skipping invocation of disabled timeout\n"); } #endif link = next; } } if (n_ready > 0) { for (i = 0; i < n_ready; i++) { DBusList **watches; DBusList *next; unsigned int condition; dbus_bool_t any_oom; /* FIXME I think this "restart if we change the watches" * approach could result in starving watches * toward the end of the list. */ if (initial_serial != loop->callback_list_serial) goto next_iteration; if (loop->depth != orig_depth) goto next_iteration; _dbus_assert (ready_fds[i].flags != 0); if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL)) { cull_watches_for_invalid_fd (loop, ready_fds[i].fd); goto next_iteration; } condition = ready_fds[i].flags; _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0); /* condition may still be 0 if we got some * weird POLLFOO thing like POLLWRBAND */ if (condition == 0) continue; watches = _dbus_hash_table_lookup_pollable (loop->watches, ready_fds[i].fd); if (watches == NULL) continue; any_oom = FALSE; for (link = _dbus_list_get_first_link (watches); link != NULL; link = next) { DBusWatch *watch = link->data; next = _dbus_list_get_next_link (watches, link); if (dbus_watch_get_enabled (watch)) { dbus_bool_t oom; oom = !dbus_watch_handle (watch, condition); if (oom) { _dbus_watch_set_oom_last_time (watch, TRUE); loop->oom_watch_pending = TRUE; any_oom = TRUE; } #if MAINLOOP_SPEW _dbus_verbose (" Invoked watch, oom = %d\n", oom); #endif retval = TRUE; /* We re-check this every time, in case the callback * added/removed watches, which might make our position in * the linked list invalid. See the FIXME above. */ if (initial_serial != loop->callback_list_serial || loop->depth != orig_depth) { if (any_oom) refresh_watches_for_fd (loop, NULL, ready_fds[i].fd); goto next_iteration; } } } if (any_oom) refresh_watches_for_fd (loop, watches, ready_fds[i].fd); } } next_iteration: #if MAINLOOP_SPEW _dbus_verbose (" moving to next iteration\n"); #endif if (_dbus_loop_dispatch (loop)) retval = TRUE; #if MAINLOOP_SPEW _dbus_verbose ("Returning %d\n", retval); #endif return retval; } void _dbus_loop_run (DBusLoop *loop) { int our_exit_depth; _dbus_assert (loop->depth >= 0); _dbus_loop_ref (loop); our_exit_depth = loop->depth; loop->depth += 1; _dbus_verbose ("Running main loop, depth %d -> %d\n", loop->depth - 1, loop->depth); while (loop->depth != our_exit_depth) _dbus_loop_iterate (loop, TRUE); _dbus_loop_unref (loop); } void _dbus_loop_quit (DBusLoop *loop) { _dbus_assert (loop->depth > 0); loop->depth -= 1; _dbus_verbose ("Quit main loop, depth %d -> %d\n", loop->depth + 1, loop->depth); } int _dbus_get_oom_wait (void) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS /* make tests go fast */ return 0; #else return 500; #endif } void _dbus_wait_for_memory (void) { _dbus_verbose ("Waiting for more memory\n"); _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ dbus-1.10.6/dbus/dbus-credentials-util.c0000644000175000017500000001460612602773110020050 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-credentials-util.c Would be in dbus-credentials.c, but only used for tests/bus * * Copyright (C) 2007 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-credentials.h" /** * @addtogroup DBusCredentials * @{ */ /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include #include static DBusCredentials* make_credentials(dbus_uid_t unix_uid, dbus_pid_t pid, const char *windows_sid) { DBusCredentials *credentials; credentials = _dbus_credentials_new (); if (unix_uid != DBUS_UID_UNSET) { if (!_dbus_credentials_add_unix_uid (credentials, unix_uid)) { _dbus_credentials_unref (credentials); return NULL; } } if (pid != DBUS_PID_UNSET) { if (!_dbus_credentials_add_pid (credentials, pid)) { _dbus_credentials_unref (credentials); return NULL; } } if (windows_sid != NULL) { if (!_dbus_credentials_add_windows_sid (credentials, windows_sid)) { _dbus_credentials_unref (credentials); return NULL; } } return credentials; } #define SAMPLE_SID "whatever a windows sid looks like" #define OTHER_SAMPLE_SID "whatever else" dbus_bool_t _dbus_credentials_test (const char *test_data_dir) { DBusCredentials *creds; DBusCredentials *creds2; if (test_data_dir == NULL) return TRUE; creds = make_credentials (12, 511, SAMPLE_SID); if (creds == NULL) _dbus_assert_not_reached ("oom"); /* test refcounting */ _dbus_credentials_ref (creds); _dbus_credentials_unref (creds); _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); _dbus_assert (_dbus_credentials_get_unix_uid (creds) == 12); _dbus_assert (_dbus_credentials_get_pid (creds) == 511); _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds), SAMPLE_SID) == 0); _dbus_assert (!_dbus_credentials_are_empty (creds)); _dbus_assert (!_dbus_credentials_are_anonymous (creds)); /* Test copy */ creds2 = _dbus_credentials_copy (creds); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_USER_ID)); _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_WINDOWS_SID)); _dbus_assert (_dbus_credentials_get_unix_uid (creds2) == 12); _dbus_assert (_dbus_credentials_get_pid (creds2) == 511); _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds2), SAMPLE_SID) == 0); _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Same user if both unix and windows are the same */ creds2 = make_credentials (12, DBUS_PID_UNSET, SAMPLE_SID); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (_dbus_credentials_same_user (creds, creds2)); _dbus_credentials_unref (creds2); /* Not the same user if Windows is missing */ creds2 = make_credentials (12, DBUS_PID_UNSET, NULL); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Not the same user if Windows is different */ creds2 = make_credentials (12, DBUS_PID_UNSET, OTHER_SAMPLE_SID); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Not the same user if Unix is missing */ creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, SAMPLE_SID); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Not the same user if Unix is different */ creds2 = make_credentials (15, DBUS_PID_UNSET, SAMPLE_SID); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Not the same user if both are missing */ creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, NULL); if (creds2 == NULL) _dbus_assert_not_reached ("oom"); _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); _dbus_credentials_unref (creds2); /* Clearing credentials works */ _dbus_credentials_clear (creds); _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); _dbus_assert (_dbus_credentials_get_unix_uid (creds) == DBUS_UID_UNSET); _dbus_assert (_dbus_credentials_get_pid (creds) == DBUS_PID_UNSET); _dbus_assert (_dbus_credentials_get_windows_sid (creds) == NULL); _dbus_assert (_dbus_credentials_are_empty (creds)); _dbus_assert (_dbus_credentials_are_anonymous (creds)); _dbus_credentials_unref (creds); return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-auth-util.c0000644000175000017500000001056412602773110016513 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-auth-util.c Would be in dbus-auth.c, but only used for tests/bus * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-auth.h" /** * @addtogroup DBusAuth * @{ */ /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-auth-script.h" #include static dbus_bool_t process_test_subdir (const DBusString *test_base_dir, const char *subdir) { DBusString test_directory; DBusString filename; DBusDirIter *dir; dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; retval = FALSE; dir = NULL; if (!_dbus_string_init (&test_directory)) _dbus_assert_not_reached ("didn't allocate test_directory\n"); _dbus_string_init_const (&filename, subdir); if (!_dbus_string_copy (test_base_dir, 0, &test_directory, 0)) _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); if (!_dbus_concat_dir_and_file (&test_directory, &filename)) _dbus_assert_not_reached ("couldn't allocate full path"); _dbus_string_free (&filename); if (!_dbus_string_init (&filename)) _dbus_assert_not_reached ("didn't allocate filename string\n"); dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { _dbus_warn ("Could not open %s: %s\n", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); goto failed; } printf ("Testing %s:\n", subdir); next: while (_dbus_directory_get_next_file (dir, &filename, &error)) { DBusString full_path; if (!_dbus_string_init (&full_path)) _dbus_assert_not_reached ("couldn't init string"); if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) _dbus_assert_not_reached ("couldn't copy dir to full_path"); if (!_dbus_concat_dir_and_file (&full_path, &filename)) _dbus_assert_not_reached ("couldn't concat file to dir"); if (!_dbus_string_ends_with_c_str (&filename, ".auth-script")) { _dbus_verbose ("Skipping non-.auth-script file %s\n", _dbus_string_get_const_data (&filename)); _dbus_string_free (&full_path); goto next; } printf (" %s\n", _dbus_string_get_const_data (&filename)); if (!_dbus_auth_script_run (&full_path)) { _dbus_string_free (&full_path); goto failed; } else _dbus_string_free (&full_path); } if (dbus_error_is_set (&error)) { _dbus_warn ("Could not get next file in %s: %s\n", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); goto failed; } retval = TRUE; failed: if (dir) _dbus_directory_close (dir); _dbus_string_free (&test_directory); _dbus_string_free (&filename); return retval; } static dbus_bool_t process_test_dirs (const char *test_data_dir) { DBusString test_directory; dbus_bool_t retval; retval = FALSE; _dbus_string_init_const (&test_directory, test_data_dir); if (!process_test_subdir (&test_directory, "auth")) goto failed; retval = TRUE; failed: _dbus_string_free (&test_directory); return retval; } dbus_bool_t _dbus_auth_test (const char *test_data_dir) { if (test_data_dir == NULL) return TRUE; if (!process_test_dirs (test_data_dir)) return FALSE; return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-auth-script.h0000644000175000017500000000237012602773110017043 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-auth-script.h Test DBusAuth using a special script file (internal to D-Bus implementation) * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_AUTH_SCRIPT_H #define DBUS_AUTH_SCRIPT_H #include #include #include DBUS_BEGIN_DECLS dbus_bool_t _dbus_auth_script_run (const DBusString *filename); DBUS_END_DECLS #endif /* DBUS_AUTH_SCRIPT_H */ dbus-1.10.6/dbus/dbus-auth-script.c0000644000175000017500000005742012622707003017044 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-auth-script.c Test DBusAuth using a special script file (internal to D-Bus implementation) * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-auth-script.h" #include #include "dbus-auth.h" #include "dbus-string.h" #include "dbus-hash.h" #include "dbus-credentials.h" #include "dbus-internals.h" /** * @defgroup DBusAuthScript code for running unit test scripts for DBusAuth * @ingroup DBusInternals * @brief DBusAuth unit test scripting * * The code in here is used for unit testing, it loads * up a script that tests DBusAuth. * * @{ */ /* this is slightly different from the other append_quoted_string * in dbus-message-builder.c */ static dbus_bool_t append_quoted_string (DBusString *dest, const DBusString *quoted) { dbus_bool_t in_quotes = FALSE; dbus_bool_t in_backslash = FALSE; int i; i = 0; while (i < _dbus_string_get_length (quoted)) { unsigned char b; b = _dbus_string_get_byte (quoted, i); if (in_backslash) { unsigned char a; if (b == 'r') a = '\r'; else if (b == 'n') a = '\n'; else if (b == '\\') a = '\\'; else { _dbus_warn ("bad backslashed byte %c\n", b); return FALSE; } if (!_dbus_string_append_byte (dest, a)) return FALSE; in_backslash = FALSE; } else if (b == '\\') { in_backslash = TRUE; } else if (in_quotes) { if (b == '\'') in_quotes = FALSE; else { if (!_dbus_string_append_byte (dest, b)) return FALSE; } } else { if (b == '\'') in_quotes = TRUE; else if (b == ' ' || b == '\n' || b == '\t') break; /* end on whitespace if not quoted */ else { if (!_dbus_string_append_byte (dest, b)) return FALSE; } } ++i; } return TRUE; } static dbus_bool_t same_first_word (const DBusString *a, const DBusString *b) { int first_a_blank, first_b_blank; _dbus_string_find_blank (a, 0, &first_a_blank); _dbus_string_find_blank (b, 0, &first_b_blank); if (first_a_blank != first_b_blank) return FALSE; return _dbus_string_equal_len (a, b, first_a_blank); } static DBusAuthState auth_state_from_string (const DBusString *str) { if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_INPUT")) return DBUS_AUTH_STATE_WAITING_FOR_INPUT; else if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_MEMORY")) return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; else if (_dbus_string_starts_with_c_str (str, "HAVE_BYTES_TO_SEND")) return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; else if (_dbus_string_starts_with_c_str (str, "NEED_DISCONNECT")) return DBUS_AUTH_STATE_NEED_DISCONNECT; else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED")) return DBUS_AUTH_STATE_AUTHENTICATED; else return -1; } static const char* auth_state_to_string (DBusAuthState state) { switch (state) { case DBUS_AUTH_STATE_WAITING_FOR_INPUT: return "WAITING_FOR_INPUT"; case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: return "WAITING_FOR_MEMORY"; case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: return "HAVE_BYTES_TO_SEND"; case DBUS_AUTH_STATE_NEED_DISCONNECT: return "NEED_DISCONNECT"; case DBUS_AUTH_STATE_AUTHENTICATED: return "AUTHENTICATED"; } return "unknown"; } static char ** split_string (DBusString *str) { int i, j, k, count, end; char **array; end = _dbus_string_get_length (str); i = 0; _dbus_string_skip_blank (str, i, &i); for (count = 0; i < end; count++) { _dbus_string_find_blank (str, i, &i); _dbus_string_skip_blank (str, i, &i); } array = dbus_new0 (char *, count + 1); if (array == NULL) return NULL; i = 0; _dbus_string_skip_blank (str, i, &i); for (k = 0; k < count; k++) { _dbus_string_find_blank (str, i, &j); array[k] = dbus_malloc (j - i + 1); if (array[k] == NULL) { dbus_free_string_array (array); return NULL; } memcpy (array[k], _dbus_string_get_const_data_len (str, i, j - i), j - i); array[k][j - i] = '\0'; _dbus_string_skip_blank (str, j, &i); } array[k] = NULL; return array; } static void auth_set_unix_credentials(DBusAuth *auth, dbus_uid_t uid, dbus_pid_t pid) { DBusCredentials *credentials; credentials = _dbus_credentials_new (); if (credentials == NULL) _dbus_assert_not_reached ("no memory"); if (uid != DBUS_UID_UNSET) { if (!_dbus_credentials_add_unix_uid (credentials, uid)) _dbus_assert_not_reached ("no memory"); } if (pid != DBUS_PID_UNSET) { if (!_dbus_credentials_add_pid (credentials, pid)) _dbus_assert_not_reached ("no memory"); } _dbus_auth_set_credentials (auth, credentials); _dbus_credentials_unref (credentials); } /** * Runs an "auth script" which is a script for testing the * authentication protocol. Scripts send and receive data, and then * include assertions about the state of both ends of the connection * after processing the data. A script succeeds if these assertions * hold. * * @param filename the file containing the script to run * @returns #TRUE if the script succeeds, #FALSE otherwise */ dbus_bool_t _dbus_auth_script_run (const DBusString *filename) { DBusString file; DBusError error = DBUS_ERROR_INIT; DBusString line; dbus_bool_t retval; int line_no; DBusAuth *auth; DBusString from_auth; DBusAuthState state; DBusString context; DBusString guid; retval = FALSE; auth = NULL; _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00"); _dbus_string_init_const (&context, "org_freedesktop_test"); if (!_dbus_string_init (&file)) return FALSE; if (!_dbus_string_init (&line)) { _dbus_string_free (&file); return FALSE; } if (!_dbus_string_init (&from_auth)) { _dbus_string_free (&file); _dbus_string_free (&line); return FALSE; } if (!_dbus_file_get_contents (&file, filename, &error)) { _dbus_warn ("Getting contents of %s failed: %s\n", _dbus_string_get_const_data (filename), error.message); dbus_error_free (&error); goto out; } state = DBUS_AUTH_STATE_NEED_DISCONNECT; line_no = 0; next_iteration: while (_dbus_string_pop_line (&file, &line)) { line_no += 1; /* _dbus_warn ("%s\n", _dbus_string_get_const_data (&line)); */ _dbus_string_delete_leading_blanks (&line); if (auth != NULL) { while ((state = _dbus_auth_do_work (auth)) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) { const DBusString *tmp; if (_dbus_auth_get_bytes_to_send (auth, &tmp)) { int count = _dbus_string_get_length (tmp); if (_dbus_string_copy (tmp, 0, &from_auth, _dbus_string_get_length (&from_auth))) _dbus_auth_bytes_sent (auth, count); } } } if (_dbus_string_get_length (&line) == 0) { /* empty line */ goto next_iteration; } else if (_dbus_string_starts_with_c_str (&line, "#")) { /* Ignore this comment */ goto next_iteration; } #ifdef DBUS_WIN else if (_dbus_string_starts_with_c_str (&line, "WIN_ONLY")) { /* Ignore this line */ goto next_iteration; } else if (_dbus_string_starts_with_c_str (&line, "UNIX_ONLY")) { /* skip this file */ fprintf (stderr, "skipping unix only auth script\n"); retval = TRUE; goto out; } #endif #ifdef DBUS_UNIX else if (_dbus_string_starts_with_c_str (&line, "UNIX_ONLY")) { /* Ignore this line */ goto next_iteration; } else if (_dbus_string_starts_with_c_str (&line, "WIN_ONLY")) { /* skip this file */ fprintf (stderr, "skipping windows only auth script\n"); retval = TRUE; goto out; } #endif else if (_dbus_string_starts_with_c_str (&line, "CLIENT")) { DBusCredentials *creds; if (auth != NULL) { _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n"); goto out; } auth = _dbus_auth_client_new (); if (auth == NULL) { _dbus_warn ("no memory to create DBusAuth\n"); goto out; } /* test ref/unref */ _dbus_auth_ref (auth); _dbus_auth_unref (auth); creds = _dbus_credentials_new_from_current_process (); if (creds == NULL) { _dbus_warn ("no memory for credentials\n"); _dbus_auth_unref (auth); auth = NULL; goto out; } if (!_dbus_auth_set_credentials (auth, creds)) { _dbus_warn ("no memory for setting credentials\n"); _dbus_auth_unref (auth); auth = NULL; _dbus_credentials_unref (creds); goto out; } _dbus_credentials_unref (creds); } else if (_dbus_string_starts_with_c_str (&line, "SERVER")) { DBusCredentials *creds; if (auth != NULL) { _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n"); goto out; } auth = _dbus_auth_server_new (&guid); if (auth == NULL) { _dbus_warn ("no memory to create DBusAuth\n"); goto out; } /* test ref/unref */ _dbus_auth_ref (auth); _dbus_auth_unref (auth); creds = _dbus_credentials_new_from_current_process (); if (creds == NULL) { _dbus_warn ("no memory for credentials\n"); _dbus_auth_unref (auth); auth = NULL; goto out; } if (!_dbus_auth_set_credentials (auth, creds)) { _dbus_warn ("no memory for setting credentials\n"); _dbus_auth_unref (auth); auth = NULL; _dbus_credentials_unref (creds); goto out; } _dbus_credentials_unref (creds); _dbus_auth_set_context (auth, &context); } else if (auth == NULL) { _dbus_warn ("must specify CLIENT or SERVER\n"); goto out; } else if (_dbus_string_starts_with_c_str (&line, "NO_CREDENTIALS")) { auth_set_unix_credentials (auth, DBUS_UID_UNSET, DBUS_PID_UNSET); } else if (_dbus_string_starts_with_c_str (&line, "ROOT_CREDENTIALS")) { auth_set_unix_credentials (auth, 0, DBUS_PID_UNSET); } else if (_dbus_string_starts_with_c_str (&line, "SILLY_CREDENTIALS")) { auth_set_unix_credentials (auth, 4312, DBUS_PID_UNSET); } else if (_dbus_string_starts_with_c_str (&line, "ALLOWED_MECHS")) { char **mechs; _dbus_string_delete_first_word (&line); mechs = split_string (&line); _dbus_auth_set_mechanisms (auth, (const char **) mechs); dbus_free_string_array (mechs); } else if (_dbus_string_starts_with_c_str (&line, "SEND")) { DBusString to_send; _dbus_string_delete_first_word (&line); if (!_dbus_string_init (&to_send)) { _dbus_warn ("no memory to allocate string\n"); goto out; } if (!append_quoted_string (&to_send, &line)) { _dbus_warn ("failed to append quoted string line %d\n", line_no); _dbus_string_free (&to_send); goto out; } _dbus_verbose ("Sending '%s'\n", _dbus_string_get_const_data (&to_send)); if (!_dbus_string_append (&to_send, "\r\n")) { _dbus_warn ("failed to append \r\n from line %d\n", line_no); _dbus_string_free (&to_send); goto out; } /* Replace USERID_HEX with our username in hex */ { int where; if (_dbus_string_find (&to_send, 0, "USERID_HEX", &where)) { DBusString username; if (!_dbus_string_init (&username)) { _dbus_warn ("no memory for userid\n"); _dbus_string_free (&to_send); goto out; } if (!_dbus_append_user_from_current_process (&username)) { _dbus_warn ("no memory for userid\n"); _dbus_string_free (&username); _dbus_string_free (&to_send); goto out; } _dbus_string_delete (&to_send, where, (int) strlen ("USERID_HEX")); if (!_dbus_string_hex_encode (&username, 0, &to_send, where)) { _dbus_warn ("no memory to subst USERID_HEX\n"); _dbus_string_free (&username); _dbus_string_free (&to_send); goto out; } _dbus_string_free (&username); } else if (_dbus_string_find (&to_send, 0, "USERNAME_HEX", &where)) { DBusString username; if (!_dbus_string_init (&username)) { _dbus_warn ("no memory for username\n"); _dbus_string_free (&to_send); goto out; } if (!_dbus_append_user_from_current_process (&username)) { _dbus_warn ("no memory for username\n"); _dbus_string_free (&username); _dbus_string_free (&to_send); goto out; } _dbus_string_delete (&to_send, where, (int) strlen ("USERNAME_HEX")); if (!_dbus_string_hex_encode (&username, 0, &to_send, where)) { _dbus_warn ("no memory to subst USERNAME_HEX\n"); _dbus_string_free (&username); _dbus_string_free (&to_send); goto out; } _dbus_string_free (&username); } } { DBusString *buffer; _dbus_auth_get_buffer (auth, &buffer); if (!_dbus_string_copy (&to_send, 0, buffer, _dbus_string_get_length (buffer))) { _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n"); _dbus_string_free (&to_send); _dbus_auth_return_buffer (auth, buffer); goto out; } _dbus_auth_return_buffer (auth, buffer); } _dbus_string_free (&to_send); } else if (_dbus_string_starts_with_c_str (&line, "EXPECT_STATE")) { DBusAuthState expected; _dbus_string_delete_first_word (&line); expected = auth_state_from_string (&line); if (expected < 0) { _dbus_warn ("bad auth state given to EXPECT_STATE\n"); goto parse_failed; } if (expected != state) { _dbus_warn ("expected auth state %s but got %s on line %d\n", auth_state_to_string (expected), auth_state_to_string (state), line_no); goto out; } } else if (_dbus_string_starts_with_c_str (&line, "EXPECT_COMMAND")) { DBusString received; _dbus_string_delete_first_word (&line); if (!_dbus_string_init (&received)) { _dbus_warn ("no mem to allocate string received\n"); goto out; } if (!_dbus_string_pop_line (&from_auth, &received)) { _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n", _dbus_string_get_const_data (&line), line_no); _dbus_string_free (&received); goto out; } if (!same_first_word (&received, &line)) { _dbus_warn ("line %d expected command '%s' and got '%s'\n", line_no, _dbus_string_get_const_data (&line), _dbus_string_get_const_data (&received)); _dbus_string_free (&received); goto out; } _dbus_string_free (&received); } else if (_dbus_string_starts_with_c_str (&line, "EXPECT_UNUSED")) { DBusString expected; const DBusString *unused; _dbus_string_delete_first_word (&line); if (!_dbus_string_init (&expected)) { _dbus_warn ("no mem to allocate string expected\n"); goto out; } if (!append_quoted_string (&expected, &line)) { _dbus_warn ("failed to append quoted string line %d\n", line_no); _dbus_string_free (&expected); goto out; } _dbus_auth_get_unused_bytes (auth, &unused); if (_dbus_string_equal (&expected, unused)) { _dbus_auth_delete_unused_bytes (auth); _dbus_string_free (&expected); } else { _dbus_warn ("Expected unused bytes '%s' and have '%s'\n", _dbus_string_get_const_data (&expected), _dbus_string_get_const_data (unused)); _dbus_string_free (&expected); goto out; } } else if (_dbus_string_starts_with_c_str (&line, "EXPECT_HAVE_NO_CREDENTIALS")) { DBusCredentials *authorized_identity; authorized_identity = _dbus_auth_get_identity (auth); if (!_dbus_credentials_are_anonymous (authorized_identity)) { _dbus_warn ("Expected anonymous login or failed login, but some credentials were authorized\n"); goto out; } } else if (_dbus_string_starts_with_c_str (&line, "EXPECT_HAVE_SOME_CREDENTIALS")) { DBusCredentials *authorized_identity; authorized_identity = _dbus_auth_get_identity (auth); if (_dbus_credentials_are_anonymous (authorized_identity)) { _dbus_warn ("Expected to have some credentials, but we don't\n"); goto out; } } else if (_dbus_string_starts_with_c_str (&line, "EXPECT")) { DBusString expected; _dbus_string_delete_first_word (&line); if (!_dbus_string_init (&expected)) { _dbus_warn ("no mem to allocate string expected\n"); goto out; } if (!append_quoted_string (&expected, &line)) { _dbus_warn ("failed to append quoted string line %d\n", line_no); _dbus_string_free (&expected); goto out; } if (_dbus_string_equal_len (&expected, &from_auth, _dbus_string_get_length (&expected))) { _dbus_string_delete (&from_auth, 0, _dbus_string_get_length (&expected)); _dbus_string_free (&expected); } else { _dbus_warn ("Expected exact string '%s' and have '%s'\n", _dbus_string_get_const_data (&expected), _dbus_string_get_const_data (&from_auth)); _dbus_string_free (&expected); goto out; } } else goto parse_failed; goto next_iteration; /* skip parse_failed */ parse_failed: { _dbus_warn ("couldn't process line %d \"%s\"\n", line_no, _dbus_string_get_const_data (&line)); goto out; } } if (auth == NULL) { _dbus_warn ("Auth script is bogus, did not even have CLIENT or SERVER\n"); goto out; } else if (state == DBUS_AUTH_STATE_AUTHENTICATED) { const DBusString *unused; _dbus_auth_get_unused_bytes (auth, &unused); if (_dbus_string_get_length (unused) > 0) { _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n"); goto out; } } if (_dbus_string_get_length (&from_auth) > 0) { _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n"); _dbus_warn ("Leftover data: %s\n", _dbus_string_get_const_data (&from_auth)); goto out; } retval = TRUE; out: if (auth) _dbus_auth_unref (auth); _dbus_string_free (&file); _dbus_string_free (&line); _dbus_string_free (&from_auth); return retval; } /** @} */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-asv-util.h0000644000175000017500000000420412602773110016342 0ustar00smcvsmcv00000000000000/* dbus-asv-util.h - utility functions for a{sv} * * Copyright © 2011-2012 Nokia Corporation * Copyright © 2012-2013 Collabora Ltd. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #ifndef DBUS_ASV_UTIL_H #define DBUS_ASV_UTIL_H #include DBUS_BEGIN_DECLS DBusMessage *_dbus_asv_new_method_return (DBusMessage *message, DBusMessageIter *iter, DBusMessageIter *arr_iter); dbus_bool_t _dbus_asv_close (DBusMessageIter *iter, DBusMessageIter *arr_iter); void _dbus_asv_abandon (DBusMessageIter *iter, DBusMessageIter *arr_iter); dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter, const char *key, dbus_uint32_t value); dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter, const char *key, const char *value); dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter, const char *key, const void *value, int n_elements); #endif dbus-1.10.6/dbus/dbus-asv-util.c0000644000175000017500000002410712602773110016341 0ustar00smcvsmcv00000000000000/* dbus-asv-util.c - utility functions for a{sv} * * Copyright © 2011-2012 Nokia Corporation * Copyright © 2012-2013 Collabora Ltd. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include #include "dbus/dbus-asv-util.h" /** * Convenience function to create a method-call reply whose type is a{sv} * (map from string to variant). * * Append values with 0 or more sequences of _dbus_asv_open_entry(), * appending a value to var_iter, and _dbus_asv_close_entry(), * then close the a{sv} with _dbus_asv_close() or _dbus_asv_abandon(). * * This must be paired with a call to _dbus_asv_close() or _dbus_asv_abandon(). * * @param message a method call message * @param iter an iterator which will be initialized to append to the message * @param arr_iter an iterator which will be initialized to append to the array * @returns a new message, or #NULL if not enough memory */ DBusMessage * _dbus_asv_new_method_return (DBusMessage *message, DBusMessageIter *iter, DBusMessageIter *arr_iter) { DBusMessage *reply = dbus_message_new_method_return (message); if (reply == NULL) return NULL; dbus_message_iter_init_append (reply, iter); if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", arr_iter)) { dbus_message_unref (reply); return NULL; } return reply; } /* * Open a new entry in an a{sv} (map from string to variant). * * This must be paired with a call to either _dbus_asv_close_entry() * or _dbus_asv_abandon_entry(). * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param entry_iter will be initialized to append to the dict-entry * @param key a UTF-8 key for the map * @param type the type of the variant value, e.g. DBUS_TYPE_STRING_AS_STRING * @param var_iter will be initialized to append (i.e. write) to the variant * @returns #TRUE on success, or #FALSE if not enough memory */ static dbus_bool_t _dbus_asv_open_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, const char *key, const char *type, DBusMessageIter *var_iter) { if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY, NULL, entry_iter)) return FALSE; if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT, type, var_iter)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } return TRUE; } /* * Closes an a{sv} entry after successfully appending the value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param entry_iter the iterator appending to the dict-entry, will be closed * @param var_iter the iterator appending to the variant, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ static dbus_bool_t _dbus_asv_close_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, DBusMessageIter *var_iter) { if (!dbus_message_iter_close_container (entry_iter, var_iter)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } if (!dbus_message_iter_close_container (arr_iter, entry_iter)) return FALSE; return TRUE; } /** * Closes an a{sv} after successfully appending all values. * * If this function fails, you must abandon iter and whatever * larger data structure (message, etc.) the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_close (DBusMessageIter *iter, DBusMessageIter *arr_iter) { return dbus_message_iter_close_container (iter, arr_iter); } /* * Closes an a{sv} entry after unsuccessfully appending a value. * You must also abandon the a{sv} itself (for instance with * _dbus_asv_abandon()), and abandon whatever larger data structure * the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ static void _dbus_asv_abandon_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, DBusMessageIter *var_iter) { dbus_message_iter_abandon_container (entry_iter, var_iter); dbus_message_iter_abandon_container (arr_iter, entry_iter); } /** * Closes an a{sv} after unsuccessfully appending a value. * * You must also abandon whatever larger data structure (message, etc.) * the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed */ void _dbus_asv_abandon (DBusMessageIter *iter, DBusMessageIter *arr_iter) { dbus_message_iter_abandon_container (iter, arr_iter); } /** * Create a new entry in an a{sv} (map from string to variant) * with a 32-bit unsigned integer value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter, const char *key, dbus_uint32_t value) { DBusMessageIter entry_iter, var_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, DBUS_TYPE_UINT32_AS_STRING, &var_iter)) return FALSE; if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32, &value)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; } /** * Create a new entry in an a{sv} (map from string to variant) * with a UTF-8 string value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter, const char *key, const char *value) { DBusMessageIter entry_iter, var_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, DBUS_TYPE_STRING_AS_STRING, &var_iter)) return FALSE; if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING, &value)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; } /** * Create a new entry in an a{sv} (map from string to variant) * with a byte array value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @param n_elements the number of elements to append * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter, const char *key, const void *value, int n_elements) { DBusMessageIter entry_iter; DBusMessageIter var_iter; DBusMessageIter byte_array_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, "ay", &var_iter)) return FALSE; if (!dbus_message_iter_open_container (&var_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &byte_array_iter)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!dbus_message_iter_append_fixed_array (&byte_array_iter, DBUS_TYPE_BYTE, &value, n_elements)) { dbus_message_iter_abandon_container (&var_iter, &byte_array_iter); _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!dbus_message_iter_close_container (&var_iter, &byte_array_iter)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; } dbus-1.10.6/dbus/dbus-init-win.cpp0000644000175000017500000000253012602773110016667 0ustar00smcvsmcv00000000000000/* * dbus-init-win.cpp - once-per-process initialization * * Copyright © 2013 Intel Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include extern "C" { #include "dbus-sysdeps-win.h" } class DBusInternalInit { public: DBusInternalInit () { _dbus_threads_windows_init_global (); } void must_not_be_omitted () { } }; static DBusInternalInit init; extern "C" void _dbus_threads_windows_ensure_ctor_linked () { /* Do nothing significant, just ensure that the global initializer gets * linked in. */ init.must_not_be_omitted (); } dbus-1.10.6/dbus/dbus-valgrind-internal.h0000644000175000017500000000367412602773110020230 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-valgrind-internal.h - valgrind glue * * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * */ #ifndef DBUS_VALGRIND_INTERNAL_H #define DBUS_VALGRIND_INTERNAL_H #include "config.h" #include "dbus-internals.h" #ifdef WITH_VALGRIND # include # include #else # define VALGRIND_CREATE_MEMPOOL(_1, _2, _3) do { } while (0) # define VALGRIND_DESTROY_MEMPOOL(_1) do { } while (0) # define VALGRIND_MEMPOOL_ALLOC(_1, _2, _3) do { } while (0) # define VALGRIND_MEMPOOL_FREE(_1, _2) do { } while (0) /* Recent gcc will warn if you have a statement that's just a macro * expanding to (0), but not if you have an inline stub function that * always returns 0, so let's do the latter. */ static inline int VALGRIND_MAKE_MEM_UNDEFINED (void *addr, size_t len) { return 0; } static inline int VALGRIND_PRINTF (const char *format, ...) { return 0; } static inline int VALGRIND_PRINTF_BACKTRACE (const char *format, ...) { return 0; } # define RUNNING_ON_VALGRIND 0 #endif /* WITH_VALGRIND */ #endif /* header guard */ dbus-1.10.6/dbus/dbus-sysdeps.h0000644000175000017500000006070012624705346016305 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.h Wrappers around system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SYSDEPS_H #define DBUS_SYSDEPS_H #ifndef VERSION #warning Please include config.h before dbus-sysdeps.h #include "config.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include /* this is perhaps bogus, but strcmp() etc. are faster if we use the * stuff straight out of string.h, so have this here for now. */ #include #include /* AIX sys/poll.h does #define events reqevents, and other * wonderousness, so must include sys/poll before declaring * DBusPollFD */ #ifdef HAVE_POLL #include #endif #ifdef DBUS_WINCE /* Windows CE lacks some system functions (such as errno and clock). We bring them in here. */ #include "dbus-sysdeps-wince-glue.h" #endif #ifdef DBUS_WIN #include #endif DBUS_BEGIN_DECLS #ifdef DBUS_WIN #define _DBUS_PATH_SEPARATOR ";" #else #define _DBUS_PATH_SEPARATOR ":" #endif /* Forward declarations */ /** An opaque list type */ typedef struct DBusList DBusList; /** Object that contains a list of credentials such as UNIX or Windows user ID */ typedef struct DBusCredentials DBusCredentials; /** A wrapper around a pipe descriptor or handle */ typedef struct DBusPipe DBusPipe; /** * @addtogroup DBusSysdeps * * @{ */ void _dbus_abort (void) _DBUS_GNUC_NORETURN; dbus_bool_t _dbus_check_setuid (void); DBUS_PRIVATE_EXPORT const char* _dbus_getenv (const char *varname); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_clearenv (void); char ** _dbus_get_environment (void); /** A process ID */ typedef unsigned long dbus_pid_t; /** A user ID */ typedef unsigned long dbus_uid_t; /** A group ID */ typedef unsigned long dbus_gid_t; /** an invalid PID used to represent an uninitialized dbus_pid_t field */ #define DBUS_PID_UNSET ((dbus_pid_t) -1) /** an invalid UID used to represent an uninitialized dbus_uid_t field */ #define DBUS_UID_UNSET ((dbus_uid_t) -1) /** an invalid GID used to represent an uninitialized dbus_gid_t field */ #define DBUS_GID_UNSET ((dbus_gid_t) -1) /** an appropriate printf format for dbus_pid_t */ #define DBUS_PID_FORMAT "%lu" /** an appropriate printf format for dbus_uid_t */ #define DBUS_UID_FORMAT "%lu" /** an appropriate printf format for dbus_gid_t */ #define DBUS_GID_FORMAT "%lu" /** * Socket interface */ #ifdef DBUS_WIN typedef struct { SOCKET sock; } DBusSocket; # define DBUS_SOCKET_FORMAT "Iu" # define DBUS_SOCKET_INIT { INVALID_SOCKET } static inline SOCKET _dbus_socket_printable (DBusSocket s) { return s.sock; } static inline dbus_bool_t _dbus_socket_is_valid (DBusSocket s) { return s.sock != INVALID_SOCKET; } static inline void _dbus_socket_invalidate (DBusSocket *s) { s->sock = INVALID_SOCKET; } static inline int _dbus_socket_get_int (DBusSocket s) { return (int)s.sock; } #else /* not DBUS_WIN */ typedef struct { int fd; } DBusSocket; # define DBUS_SOCKET_FORMAT "d" # define DBUS_SOCKET_INIT { -1 } static inline int _dbus_socket_printable (DBusSocket s) { return s.fd; } static inline dbus_bool_t _dbus_socket_is_valid (DBusSocket s) { return s.fd >= 0; } static inline void _dbus_socket_invalidate (DBusSocket *s) { s->fd = -1; } static inline int _dbus_socket_get_int (DBusSocket s) { return s.fd; } #endif /* not DBUS_WIN */ static inline DBusSocket _dbus_socket_get_invalid (void) { DBusSocket s = DBUS_SOCKET_INIT; return s; } dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket fd, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_close_socket (DBusSocket fd, DBusError *error); DBUS_PRIVATE_EXPORT int _dbus_read_socket (DBusSocket fd, DBusString *buffer, int count); DBUS_PRIVATE_EXPORT int _dbus_write_socket (DBusSocket fd, const DBusString *buffer, int start, int len); int _dbus_write_socket_two (DBusSocket fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2); int _dbus_read_socket_with_unix_fds (DBusSocket fd, DBusString *buffer, int count, int *fds, int *n_fds); DBUS_PRIVATE_EXPORT int _dbus_write_socket_with_unix_fds (DBusSocket fd, const DBusString *buffer, int start, int len, const int *fds, int n_fds); int _dbus_write_socket_with_unix_fds_two (DBusSocket fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2, const int *fds, int n_fds); DBusSocket _dbus_connect_tcp_socket (const char *host, const char *port, const char *family, DBusError *error); DBusSocket _dbus_connect_tcp_socket_with_nonce (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error); int _dbus_listen_tcp_socket (const char *host, const char *port, const char *family, DBusString *retport, DBusSocket **fds_p, DBusError *error); DBusSocket _dbus_accept (DBusSocket listen_fd); dbus_bool_t _dbus_read_credentials_socket (DBusSocket client_fd, DBusCredentials *credentials, DBusError *error); dbus_bool_t _dbus_send_credentials_socket (DBusSocket server_fd, DBusError *error); dbus_bool_t _dbus_credentials_add_from_user (DBusCredentials *credentials, const DBusString *username); dbus_bool_t _dbus_credentials_add_from_current_process (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_append_user_from_current_process (DBusString *str); dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username, dbus_uid_t *uid_p); dbus_bool_t _dbus_parse_unix_group_from_config (const DBusString *groupname, dbus_gid_t *gid_p); dbus_bool_t _dbus_unix_groups_from_uid (dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids); dbus_bool_t _dbus_unix_user_is_at_console (dbus_uid_t uid, DBusError *error); dbus_bool_t _dbus_unix_user_is_process_owner (dbus_uid_t uid); dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid); dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString *directory, DBusCredentials *credentials); dbus_bool_t _dbus_daemon_is_session_bus_address_published (const char *scope); dbus_bool_t _dbus_daemon_publish_session_bus_address (const char* address, const char* shm_name); void _dbus_daemon_unpublish_session_bus_address (void); dbus_bool_t _dbus_socket_can_pass_unix_fd(DBusSocket fd); /** Opaque type representing an atomically-modifiable integer * that can be used from multiple threads. */ typedef struct DBusAtomic DBusAtomic; /** * An atomic integer safe to increment or decrement from multiple threads. */ struct DBusAtomic { #ifdef DBUS_WIN volatile long value; /**< Value of the atomic integer. */ #else volatile dbus_int32_t value; /**< Value of the atomic integer. */ #endif }; /* The value we get from autofoo is in the form of a cpp expression; * convert that to a conventional defined/undef switch. (We can't get * the conventional defined/undef because of multiarch builds only running * ./configure once, on Darwin.) */ #if DBUS_HAVE_ATOMIC_INT_COND # define DBUS_HAVE_ATOMIC_INT 1 #else # undef DBUS_HAVE_ATOMIC_INT #endif dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic); dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic); dbus_int32_t _dbus_atomic_get (DBusAtomic *atomic); #ifdef DBUS_WIN /* On Windows, you can only poll sockets. We emulate Unix poll() using * select(), so it doesn't matter what precise type we put in DBusPollFD; * use DBusSocket so that the compiler can check we are doing it right. */ typedef DBusSocket DBusPollable; # define DBUS_POLLABLE_FORMAT "Iu" static inline DBusPollable _dbus_socket_get_pollable (DBusSocket s) { return s; } static inline SOCKET _dbus_pollable_printable (DBusPollable p) { return p.sock; } static inline dbus_bool_t _dbus_pollable_is_valid (DBusPollable p) { return _dbus_socket_is_valid (p); } static inline void _dbus_pollable_invalidate (DBusPollable *p) { _dbus_socket_invalidate (p); } static inline dbus_bool_t _dbus_pollable_equals (DBusPollable a, DBusPollable b) { return a.sock == b.sock; } #else /* !DBUS_WIN */ /* On Unix, you can poll sockets, pipes, etc., and we must put exactly * "int" in DBusPollFD because we're relying on its layout exactly matching * struct pollfd. (This is silly, and one day we should use a better * abstraction.) */ typedef int DBusPollable; # define DBUS_POLLABLE_FORMAT "d" static inline DBusPollable _dbus_socket_get_pollable (DBusSocket s) { return s.fd; } static inline int _dbus_pollable_printable (DBusPollable p) { return p; } static inline dbus_bool_t _dbus_pollable_is_valid (DBusPollable p) { return p >= 0; } static inline void _dbus_pollable_invalidate (DBusPollable *p) { *p = -1; } static inline dbus_bool_t _dbus_pollable_equals (DBusPollable a, DBusPollable b) { return a == b; } #endif /* !DBUS_WIN */ #if defined(HAVE_POLL) && !defined(BROKEN_POLL) /** * A portable struct pollfd wrapper, or an emulation of struct pollfd * on platforms where poll() is missing or broken. */ typedef struct pollfd DBusPollFD; /** There is data to read */ #define _DBUS_POLLIN POLLIN /** There is urgent data to read */ #define _DBUS_POLLPRI POLLPRI /** Writing now will not block */ #define _DBUS_POLLOUT POLLOUT /** Error condition */ #define _DBUS_POLLERR POLLERR /** Hung up */ #define _DBUS_POLLHUP POLLHUP /** Invalid request: fd not open */ #define _DBUS_POLLNVAL POLLNVAL #else /* Emulate poll() via select(). Because we aren't really going to call * poll(), any similarly-shaped struct is acceptable, and any power of 2 * will do for the events/revents; these values happen to match Linux * and *BSD. */ typedef struct { DBusPollable fd; /**< File descriptor */ short events; /**< Events to poll for */ short revents; /**< Events that occurred */ } DBusPollFD; /** There is data to read */ #define _DBUS_POLLIN 0x0001 /** There is urgent data to read */ #define _DBUS_POLLPRI 0x0002 /** Writing now will not block */ #define _DBUS_POLLOUT 0x0004 /** Error condition */ #define _DBUS_POLLERR 0x0008 /** Hung up */ #define _DBUS_POLLHUP 0x0010 /** Invalid request: fd not open */ #define _DBUS_POLLNVAL 0x0020 #endif DBUS_PRIVATE_EXPORT int _dbus_poll (DBusPollFD *fds, int n_fds, int timeout_milliseconds); DBUS_PRIVATE_EXPORT void _dbus_sleep_milliseconds (int milliseconds); DBUS_PRIVATE_EXPORT void _dbus_get_monotonic_time (long *tv_sec, long *tv_usec); DBUS_PRIVATE_EXPORT void _dbus_get_real_time (long *tv_sec, long *tv_usec); /** * directory interface */ DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_create_directory (const DBusString *filename, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_delete_directory (const DBusString *filename, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir, const DBusString *next_component); dbus_bool_t _dbus_string_get_dirname (const DBusString *filename, DBusString *dirname); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_path_is_absolute (const DBusString *filename); dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs); dbus_bool_t _dbus_get_standard_system_servicedirs (DBusList **dirs); dbus_bool_t _dbus_append_system_config_file (DBusString *str); dbus_bool_t _dbus_append_session_config_file (DBusString *str); /** Opaque type for reading a directory listing */ typedef struct DBusDirIter DBusDirIter; DBusDirIter* _dbus_directory_open (const DBusString *filename, DBusError *error); dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, DBusError *error); void _dbus_directory_close (DBusDirIter *iter); dbus_bool_t _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error); DBUS_PRIVATE_EXPORT const char* _dbus_get_tmpdir (void); /** * Random numbers */ _DBUS_GNUC_WARN_UNUSED_RESULT dbus_bool_t _dbus_generate_random_bytes_buffer (char *buffer, int n_bytes, DBusError *error); dbus_bool_t _dbus_generate_random_bytes (DBusString *str, int n_bytes, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_generate_random_ascii (DBusString *str, int n_bytes, DBusError *error); DBUS_PRIVATE_EXPORT const char* _dbus_error_from_errno (int error_number); DBUS_PRIVATE_EXPORT const char* _dbus_error_from_system_errno (void); int _dbus_save_socket_errno (void); void _dbus_restore_socket_errno (int saved_errno); void _dbus_set_errno_to_zero (void); dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (int e); dbus_bool_t _dbus_get_is_errno_enomem (int e); dbus_bool_t _dbus_get_is_errno_eintr (int e); dbus_bool_t _dbus_get_is_errno_epipe (int e); dbus_bool_t _dbus_get_is_errno_etoomanyrefs (int e); DBUS_PRIVATE_EXPORT const char* _dbus_strerror_from_errno (void); void _dbus_disable_sigpipe (void); DBUS_PRIVATE_EXPORT void _dbus_exit (int code) _DBUS_GNUC_NORETURN; DBUS_PRIVATE_EXPORT int _dbus_printf_string_upper_bound (const char *format, va_list args); /** * Portable struct with stat() results */ typedef struct { unsigned long mode; /**< File mode */ unsigned long nlink; /**< Number of hard links */ dbus_uid_t uid; /**< User owning file */ dbus_gid_t gid; /**< Group owning file */ unsigned long size; /**< Size of file */ unsigned long atime; /**< Access time */ unsigned long mtime; /**< Modify time */ unsigned long ctime; /**< Creation time */ } DBusStat; dbus_bool_t _dbus_stat (const DBusString *filename, DBusStat *statbuf, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_socketpair (DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error); void _dbus_print_backtrace (void); dbus_bool_t _dbus_become_daemon (const DBusString *pidfile, DBusPipe *print_pid_pipe, DBusError *error, dbus_bool_t keep_umask); dbus_bool_t _dbus_verify_daemon_user (const char *user); dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error); dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, DBusPipe *print_pid_pipe, dbus_pid_t pid_to_write, DBusError *error); dbus_bool_t _dbus_command_for_pid (unsigned long pid, DBusString *str, int max_len, DBusError *error); /** A UNIX signal handler */ typedef void (* DBusSignalHandler) (int sig); void _dbus_set_signal_handler (int sig, DBusSignalHandler handler); dbus_bool_t _dbus_user_at_console (const char *username, DBusError *error); void _dbus_init_system_log (dbus_bool_t is_daemon); typedef enum { DBUS_SYSTEM_LOG_INFO, DBUS_SYSTEM_LOG_WARNING, DBUS_SYSTEM_LOG_SECURITY, DBUS_SYSTEM_LOG_FATAL } DBusSystemLogSeverity; void _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (2, 3); void _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args); /* Define DBUS_VA_COPY() to do the right thing for copying va_list variables. * config.h may have already defined DBUS_VA_COPY as va_copy or __va_copy. */ #if !defined (DBUS_VA_COPY) # if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32)) # define DBUS_VA_COPY(ap1, ap2) (*(ap1) = *(ap2)) # elif defined (DBUS_VA_COPY_AS_ARRAY) # define DBUS_VA_COPY(ap1, ap2) memcpy ((ap1), (ap2), sizeof (va_list)) # else /* va_list is a pointer */ # define DBUS_VA_COPY(ap1, ap2) ((ap1) = (ap2)) # endif /* va_list is a pointer */ #endif /* !DBUS_VA_COPY */ /** * Casts a primitive C type to a byte array and then indexes * a particular byte of the array. */ #define _DBUS_BYTE_OF_PRIMITIVE(p, i) \ (((const char*)&(p))[(i)]) /** On x86 there is an 80-bit FPU, and if you do "a == b" it may have a * or b in an 80-bit register, thus failing to compare the two 64-bit * doubles for bitwise equality. So this macro compares the two doubles * bitwise. */ #define _DBUS_DOUBLES_BITWISE_EQUAL(a, b) \ (_DBUS_BYTE_OF_PRIMITIVE (a, 0) == _DBUS_BYTE_OF_PRIMITIVE (b, 0) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 1) == _DBUS_BYTE_OF_PRIMITIVE (b, 1) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 2) == _DBUS_BYTE_OF_PRIMITIVE (b, 2) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 3) == _DBUS_BYTE_OF_PRIMITIVE (b, 3) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 4) == _DBUS_BYTE_OF_PRIMITIVE (b, 4) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 5) == _DBUS_BYTE_OF_PRIMITIVE (b, 5) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 6) == _DBUS_BYTE_OF_PRIMITIVE (b, 6) && \ _DBUS_BYTE_OF_PRIMITIVE (a, 7) == _DBUS_BYTE_OF_PRIMITIVE (b, 7)) dbus_bool_t _dbus_get_autolaunch_address (const char *scope, DBusString *address, DBusError *error); dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported, DBusString *address, DBusError *error); /** Type representing a universally unique ID * @todo rename to UUID instead of GUID */ typedef union DBusGUID DBusGUID; dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, dbus_bool_t create_if_not_found, DBusError *error); /** * Initialize threads as in dbus_threads_init_default(), appropriately * for the platform. * @returns #FALSE if no memory */ dbus_bool_t _dbus_threads_init_platform_specific (void); /** * Lock a static mutex used to protect _dbus_threads_init_platform_specific(). */ void _dbus_threads_lock_platform_specific (void); /** * Undo _dbus_threads_lock_platform_specific(). */ void _dbus_threads_unlock_platform_specific (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, const char *suffix, DBusList **dir_list); unsigned long _dbus_pid_for_log (void); /* FIXME move back to dbus-sysdeps-unix.h probably - * the PID file handling just needs a little more abstraction * in the bus daemon first. */ DBUS_PRIVATE_EXPORT dbus_pid_t _dbus_getpid (void); DBUS_PRIVATE_EXPORT dbus_uid_t _dbus_getuid (void); dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error); DBUS_PRIVATE_EXPORT void _dbus_flush_caches (void); /* * replaces the term DBUS_PREFIX in configure_time_path by the * current dbus installation directory. On unix this function is a noop * * @param configure_time_path * @return real path */ const char * _dbus_replace_install_prefix (const char *configure_time_path); /* Do not set this too high: it is a denial-of-service risk. * See * * (This needs to be in the non-Unix-specific header so that * the config-parser can use it.) */ #define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16 typedef struct DBusRLimit DBusRLimit; DBusRLimit *_dbus_rlimit_save_fd_limit (DBusError *error); dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, DBusError *error); dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, DBusError *error); void _dbus_rlimit_free (DBusRLimit *lim); /** @} */ DBUS_END_DECLS #ifdef DBUS_WIN #include "dbus-sysdeps-win.h" #endif #endif /* DBUS_SYSDEPS_H */ dbus-1.10.6/dbus/dbus-sysdeps.c0000644000175000017500000004227112602773110016271 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-list.h" #include "dbus-misc.h" /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c. * * These are the standard ANSI C headers... */ #if HAVE_LOCALE_H #include #endif #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef DBUS_WIN #include #elif (defined __APPLE__) # include # define environ (*_NSGetEnviron()) #else extern char **environ; #endif /** * @defgroup DBusSysdeps Internal system-dependent API * @ingroup DBusInternals * @brief Internal system-dependent API available on UNIX and Windows * * The system-dependent API has a dual purpose. First, it encapsulates * all usage of operating system APIs for ease of auditing and to * avoid cluttering the rest of the code with bizarre OS quirks and * headers. Second, it abstracts different operating system APIs for * portability. * * @{ */ /** * Aborts the program with SIGABRT (dumping core). */ void _dbus_abort (void) { const char *s; _dbus_print_backtrace (); s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT"); if (s && *s) { /* don't use _dbus_warn here since it can _dbus_abort() */ fprintf (stderr, " Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ()); _dbus_sleep_milliseconds (1000 * 180); } abort (); _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */ } /** * @ingroup DBusMisc * * Wrapper for setenv(). If the value is #NULL, unsets * the environment variable. * * There is an unfixable memleak in that it is unsafe to * free memory malloced for use with setenv. This is because * we can not rely on internal implementation details of * the underlying libc library. * * This function is not thread-safe, because altering the environment * in Unix is not thread-safe in general. * * @param varname name of environment variable * @param value value of environment variable, or #NULL to unset * @returns #TRUE on success, #FALSE if not enough memory. */ dbus_bool_t dbus_setenv (const char *varname, const char *value) { _dbus_assert (varname != NULL); if (value == NULL) { #ifdef HAVE_UNSETENV unsetenv (varname); return TRUE; #else char *putenv_value; size_t len; len = strlen (varname); /* Use system malloc to avoid memleaks that dbus_malloc * will get upset about. */ putenv_value = malloc (len + 2); if (putenv_value == NULL) return FALSE; strcpy (putenv_value, varname); #if defined(DBUS_WIN) strcat (putenv_value, "="); #endif return (putenv (putenv_value) == 0); #endif } else { #ifdef HAVE_SETENV return (setenv (varname, value, TRUE) == 0); #else char *putenv_value; size_t len; size_t varname_len; size_t value_len; varname_len = strlen (varname); value_len = strlen (value); len = varname_len + value_len + 1 /* '=' */ ; /* Use system malloc to avoid memleaks that dbus_malloc * will get upset about. */ putenv_value = malloc (len + 1); if (putenv_value == NULL) return FALSE; strcpy (putenv_value, varname); strcpy (putenv_value + varname_len, "="); strcpy (putenv_value + varname_len + 1, value); return (putenv (putenv_value) == 0); #endif } } /** * Wrapper for getenv(). * * @param varname name of environment variable * @returns value of environment variable or #NULL if unset */ const char* _dbus_getenv (const char *varname) { /* Don't respect any environment variables if the current process is * setuid. This is the equivalent of glibc's __secure_getenv(). */ if (_dbus_check_setuid ()) return NULL; return getenv (varname); } /** * Wrapper for clearenv(). * * @returns #TRUE on success. */ dbus_bool_t _dbus_clearenv (void) { dbus_bool_t rc = TRUE; #ifdef HAVE_CLEARENV if (clearenv () != 0) rc = FALSE; #else if (environ != NULL) environ[0] = NULL; #endif return rc; } /** * Split paths into a list of char strings * * @param dirs string with pathes * @param suffix string concated to each path in dirs * @param dir_list contains a list of splitted pathes * return #TRUE is pathes could be splittes,#FALSE in oom case */ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, const char *suffix, DBusList **dir_list) { int start; int i; int len; char *cpath; DBusString file_suffix; start = 0; i = 0; _dbus_string_init_const (&file_suffix, suffix); len = _dbus_string_get_length (dirs); while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i)) { DBusString path; if (!_dbus_string_init (&path)) goto oom; if (!_dbus_string_copy_len (dirs, start, i - start, &path, 0)) { _dbus_string_free (&path); goto oom; } _dbus_string_chop_white (&path); /* check for an empty path */ if (_dbus_string_get_length (&path) == 0) goto next; if (!_dbus_concat_dir_and_file (&path, &file_suffix)) { _dbus_string_free (&path); goto oom; } if (!_dbus_string_copy_data(&path, &cpath)) { _dbus_string_free (&path); goto oom; } if (!_dbus_list_append (dir_list, cpath)) { _dbus_string_free (&path); dbus_free (cpath); goto oom; } next: _dbus_string_free (&path); start = i + 1; } if (start != len) { DBusString path; if (!_dbus_string_init (&path)) goto oom; if (!_dbus_string_copy_len (dirs, start, len - start, &path, 0)) { _dbus_string_free (&path); goto oom; } if (!_dbus_concat_dir_and_file (&path, &file_suffix)) { _dbus_string_free (&path); goto oom; } if (!_dbus_string_copy_data(&path, &cpath)) { _dbus_string_free (&path); goto oom; } if (!_dbus_list_append (dir_list, cpath)) { _dbus_string_free (&path); dbus_free (cpath); goto oom; } _dbus_string_free (&path); } return TRUE; oom: _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); _dbus_list_clear (dir_list); return FALSE; } /** @} */ /** * @addtogroup DBusString * * @{ */ /** * Appends an integer to a DBusString. * * @param str the string * @param value the integer value * @returns #FALSE if not enough memory or other failure. */ dbus_bool_t _dbus_string_append_int (DBusString *str, long value) { /* this calculation is from comp.lang.c faq */ #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1) /* +1 for '-' */ int orig_len; int i; char *buf; orig_len = _dbus_string_get_length (str); if (!_dbus_string_lengthen (str, MAX_LONG_LEN)) return FALSE; buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN); snprintf (buf, MAX_LONG_LEN, "%ld", value); i = 0; while (*buf) { ++buf; ++i; } _dbus_string_shorten (str, MAX_LONG_LEN - i); return TRUE; } /** * Appends an unsigned integer to a DBusString. * * @param str the string * @param value the integer value * @returns #FALSE if not enough memory or other failure. */ dbus_bool_t _dbus_string_append_uint (DBusString *str, unsigned long value) { /* this is wrong, but definitely on the high side. */ #define MAX_ULONG_LEN (MAX_LONG_LEN * 2) int orig_len; int i; char *buf; orig_len = _dbus_string_get_length (str); if (!_dbus_string_lengthen (str, MAX_ULONG_LEN)) return FALSE; buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN); snprintf (buf, MAX_ULONG_LEN, "%lu", value); i = 0; while (*buf) { ++buf; ++i; } _dbus_string_shorten (str, MAX_ULONG_LEN - i); return TRUE; } /** * Parses an integer contained in a DBusString. Either return parameter * may be #NULL if you aren't interested in it. The integer is parsed * and stored in value_return. Return parameters are not initialized * if the function returns #FALSE. * * @param str the string * @param start the byte index of the start of the integer * @param value_return return location of the integer value or #NULL * @param end_return return location of the end of the integer, or #NULL * @returns #TRUE on success */ dbus_bool_t _dbus_string_parse_int (const DBusString *str, int start, long *value_return, int *end_return) { long v; const char *p; char *end; p = _dbus_string_get_const_data_len (str, start, _dbus_string_get_length (str) - start); end = NULL; _dbus_set_errno_to_zero (); v = strtol (p, &end, 0); if (end == NULL || end == p || errno != 0) return FALSE; if (value_return) *value_return = v; if (end_return) *end_return = start + (end - p); return TRUE; } /** * Parses an unsigned integer contained in a DBusString. Either return * parameter may be #NULL if you aren't interested in it. The integer * is parsed and stored in value_return. Return parameters are not * initialized if the function returns #FALSE. * * @param str the string * @param start the byte index of the start of the integer * @param value_return return location of the integer value or #NULL * @param end_return return location of the end of the integer, or #NULL * @returns #TRUE on success */ dbus_bool_t _dbus_string_parse_uint (const DBusString *str, int start, unsigned long *value_return, int *end_return) { unsigned long v; const char *p; char *end; p = _dbus_string_get_const_data_len (str, start, _dbus_string_get_length (str) - start); end = NULL; _dbus_set_errno_to_zero (); v = strtoul (p, &end, 0); if (end == NULL || end == p || errno != 0) return FALSE; if (value_return) *value_return = v; if (end_return) *end_return = start + (end - p); return TRUE; } /** @} */ /* DBusString group */ /** * @addtogroup DBusInternalsUtils * @{ */ /** * Fills n_bytes of the given buffer with random bytes. * * @param buffer an allocated buffer * @param n_bytes the number of bytes in buffer to write to * @param error location to store reason for failure * @returns #TRUE on success */ dbus_bool_t _dbus_generate_random_bytes_buffer (char *buffer, int n_bytes, DBusError *error) { DBusString str; if (!_dbus_string_init (&str)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_generate_random_bytes (&str, n_bytes, error)) { _dbus_string_free (&str); return FALSE; } _dbus_string_copy_to_buffer (&str, buffer, n_bytes); _dbus_string_free (&str); return TRUE; } /** * Generates the given number of random bytes, where the bytes are * chosen from the alphanumeric ASCII subset. * * @param str the string * @param n_bytes the number of random ASCII bytes to append to string * @param error location to store reason for failure * @returns #TRUE on success, #FALSE if no memory or other failure */ dbus_bool_t _dbus_generate_random_ascii (DBusString *str, int n_bytes, DBusError *error) { static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; int i; int len; if (!_dbus_generate_random_bytes (str, n_bytes, error)) return FALSE; len = _dbus_string_get_length (str); i = len - n_bytes; while (i < len) { _dbus_string_set_byte (str, i, letters[_dbus_string_get_byte (str, i) % (sizeof (letters) - 1)]); ++i; } _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes, n_bytes)); return TRUE; } /** * Converts a UNIX errno, or Windows errno or WinSock error value into * a #DBusError name. * * @todo should cover more errnos, specifically those * from open(). * * @param error_number the errno. * @returns an error name */ const char* _dbus_error_from_errno (int error_number) { switch (error_number) { case 0: return DBUS_ERROR_FAILED; #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: return DBUS_ERROR_NOT_SUPPORTED; #elif defined(WSAEPROTONOSUPPORT) case WSAEPROTONOSUPPORT: return DBUS_ERROR_NOT_SUPPORTED; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: return DBUS_ERROR_NOT_SUPPORTED; #elif defined(WSAEAFNOSUPPORT) case WSAEAFNOSUPPORT: return DBUS_ERROR_NOT_SUPPORTED; #endif #ifdef ENFILE case ENFILE: return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */ #endif #ifdef EMFILE case EMFILE: return DBUS_ERROR_LIMITS_EXCEEDED; #endif #ifdef EACCES case EACCES: return DBUS_ERROR_ACCESS_DENIED; #endif #ifdef EPERM case EPERM: return DBUS_ERROR_ACCESS_DENIED; #endif #ifdef ENOBUFS case ENOBUFS: return DBUS_ERROR_NO_MEMORY; #endif #ifdef ENOMEM case ENOMEM: return DBUS_ERROR_NO_MEMORY; #endif #ifdef ECONNREFUSED case ECONNREFUSED: return DBUS_ERROR_NO_SERVER; #elif defined(WSAECONNREFUSED) case WSAECONNREFUSED: return DBUS_ERROR_NO_SERVER; #endif #ifdef ETIMEDOUT case ETIMEDOUT: return DBUS_ERROR_TIMEOUT; #elif defined(WSAETIMEDOUT) case WSAETIMEDOUT: return DBUS_ERROR_TIMEOUT; #endif #ifdef ENETUNREACH case ENETUNREACH: return DBUS_ERROR_NO_NETWORK; #elif defined(WSAENETUNREACH) case WSAENETUNREACH: return DBUS_ERROR_NO_NETWORK; #endif #ifdef EADDRINUSE case EADDRINUSE: return DBUS_ERROR_ADDRESS_IN_USE; #elif defined(WSAEADDRINUSE) case WSAEADDRINUSE: return DBUS_ERROR_ADDRESS_IN_USE; #endif #ifdef EEXIST case EEXIST: return DBUS_ERROR_FILE_EXISTS; #endif #ifdef ENOENT case ENOENT: return DBUS_ERROR_FILE_NOT_FOUND; #endif } return DBUS_ERROR_FAILED; } /** * Converts the current system errno value into a #DBusError name. * * @returns an error name */ const char* _dbus_error_from_system_errno (void) { return _dbus_error_from_errno (errno); } /** * Assign 0 to the global errno variable */ void _dbus_set_errno_to_zero (void) { #ifdef DBUS_WINCE SetLastError (0); #else errno = 0; #endif } /** * See if errno is ENOMEM * @returns #TRUE if e == ENOMEM */ dbus_bool_t _dbus_get_is_errno_enomem (int e) { return e == ENOMEM; } /** * See if errno is EINTR * @returns #TRUE if e == EINTR */ dbus_bool_t _dbus_get_is_errno_eintr (int e) { return e == EINTR; } /** * See if errno is EPIPE * @returns #TRUE if errno == EPIPE */ dbus_bool_t _dbus_get_is_errno_epipe (int e) { return e == EPIPE; } /** * See if errno is ETOOMANYREFS * @returns #TRUE if errno == ETOOMANYREFS */ dbus_bool_t _dbus_get_is_errno_etoomanyrefs (int e) { #ifdef ETOOMANYREFS return e == ETOOMANYREFS; #else return FALSE; #endif } /** * Get error message from errno * @returns _dbus_strerror(errno) */ const char* _dbus_strerror_from_errno (void) { return _dbus_strerror (errno); } /** @} end of sysdeps */ /* tests in dbus-sysdeps-util.c */ dbus-1.10.6/dbus/dbus-transport-win.h0000644000175000017500000000224212602773110017425 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-win.h Windows socket subclasses of DBusTransport * * Copyright (C) 2002 Red Hat Inc. * Copyright (C) 2007 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TRANSPORT_WIN_H #define DBUS_TRANSPORT_WIN_H #include DBUS_BEGIN_DECLS DBUS_END_DECLS #endif /* DBUS_TRANSPORT_WIN_H */ dbus-1.10.6/dbus/dbus-transport-win.c0000644000175000017500000000371112602773110017422 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-win.c Windows socket subclasses of DBusTransport * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * Copyright (C) 2007 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-transport-socket.h" #include "dbus-transport-protected.h" #include "dbus-watch.h" #include "dbus-sysdeps-win.h" /** * @defgroup DBusTransportUnix DBusTransport implementations for UNIX * @ingroup DBusInternals * @brief Implementation details of DBusTransport on UNIX * * @{ */ /** * Opens platform specific transport types. * * @param entry the address entry to try opening * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { /* currently no Windows-specific transports */ return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } /** @} */ dbus-1.10.6/dbus/dbus-sysdeps-thread-win.c0000644000175000017500000001601312602773110020324 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus) * * Copyright (C) 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-win.h" #include "dbus-threads.h" #include "dbus-list.h" #include static dbus_bool_t global_init_done = FALSE; static CRITICAL_SECTION init_lock; /* Called from C++ code in dbus-init-win.cpp. */ void _dbus_threads_windows_init_global (void) { /* this ensures that the object that acts as our global constructor * actually gets linked in when we're linked statically */ _dbus_threads_windows_ensure_ctor_linked (); InitializeCriticalSection (&init_lock); global_init_done = TRUE; } struct DBusCondVar { DBusList *list; /**< list thread-local-stored events waiting on the cond variable */ CRITICAL_SECTION lock; /**< lock protecting the list */ }; static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES; static HMODULE dbus_dll_hmodule; void * _dbus_win_get_dll_hmodule (void) { return dbus_dll_hmodule; } #ifdef DBUS_WINCE #define hinst_t HANDLE #else #define hinst_t HINSTANCE #endif BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID); /* We need this to free the TLS events on thread exit */ BOOL WINAPI DllMain (hinst_t hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { HANDLE event; switch (fdwReason) { case DLL_PROCESS_ATTACH: dbus_dll_hmodule = hinstDLL; break; case DLL_THREAD_DETACH: if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES) { event = TlsGetValue(dbus_cond_event_tls); CloseHandle (event); TlsSetValue(dbus_cond_event_tls, NULL); } break; case DLL_PROCESS_DETACH: if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES) { event = TlsGetValue(dbus_cond_event_tls); CloseHandle (event); TlsSetValue(dbus_cond_event_tls, NULL); TlsFree(dbus_cond_event_tls); } break; default: break; } return TRUE; } DBusCMutex * _dbus_platform_cmutex_new (void) { HANDLE handle; handle = CreateMutex (NULL, FALSE, NULL); return (DBusCMutex *) handle; } DBusRMutex * _dbus_platform_rmutex_new (void) { HANDLE handle; handle = CreateMutex (NULL, FALSE, NULL); return (DBusRMutex *) handle; } void _dbus_platform_cmutex_free (DBusCMutex *mutex) { CloseHandle ((HANDLE *) mutex); } void _dbus_platform_rmutex_free (DBusRMutex *mutex) { CloseHandle ((HANDLE *) mutex); } void _dbus_platform_cmutex_lock (DBusCMutex *mutex) { WaitForSingleObject ((HANDLE *) mutex, INFINITE); } void _dbus_platform_rmutex_lock (DBusRMutex *mutex) { WaitForSingleObject ((HANDLE *) mutex, INFINITE); } void _dbus_platform_cmutex_unlock (DBusCMutex *mutex) { ReleaseMutex ((HANDLE *) mutex); } void _dbus_platform_rmutex_unlock (DBusRMutex *mutex) { ReleaseMutex ((HANDLE *) mutex); } DBusCondVar * _dbus_platform_condvar_new (void) { DBusCondVar *cond; cond = dbus_new (DBusCondVar, 1); if (cond == NULL) return NULL; cond->list = NULL; InitializeCriticalSection (&cond->lock); return cond; } void _dbus_platform_condvar_free (DBusCondVar *cond) { DeleteCriticalSection (&cond->lock); _dbus_list_clear (&cond->list); dbus_free (cond); } static dbus_bool_t _dbus_condvar_wait_win32 (DBusCondVar *cond, DBusCMutex *mutex, int milliseconds) { DWORD retval; dbus_bool_t ret; HANDLE event = TlsGetValue (dbus_cond_event_tls); if (!event) { event = CreateEvent (0, FALSE, FALSE, NULL); if (event == 0) return FALSE; TlsSetValue (dbus_cond_event_tls, event); } EnterCriticalSection (&cond->lock); /* The event must not be signaled. Check this */ _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT); ret = _dbus_list_append (&cond->list, event); LeaveCriticalSection (&cond->lock); if (!ret) return FALSE; /* Prepend failed */ _dbus_platform_cmutex_unlock (mutex); retval = WaitForSingleObject (event, milliseconds); _dbus_platform_cmutex_lock (mutex); if (retval == WAIT_TIMEOUT) { EnterCriticalSection (&cond->lock); _dbus_list_remove (&cond->list, event); /* In the meantime we could have been signaled, so we must again * wait for the signal, this time with no timeout, to reset * it. retval is set again to honour the late arrival of the * signal */ retval = WaitForSingleObject (event, 0); LeaveCriticalSection (&cond->lock); } #ifndef DBUS_DISABLE_ASSERT EnterCriticalSection (&cond->lock); /* Now event must not be inside the array, check this */ _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE); LeaveCriticalSection (&cond->lock); #endif /* !G_DISABLE_ASSERT */ return retval != WAIT_TIMEOUT; } void _dbus_platform_condvar_wait (DBusCondVar *cond, DBusCMutex *mutex) { _dbus_condvar_wait_win32 (cond, mutex, INFINITE); } dbus_bool_t _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, DBusCMutex *mutex, int timeout_milliseconds) { return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds); } void _dbus_platform_condvar_wake_one (DBusCondVar *cond) { EnterCriticalSection (&cond->lock); if (cond->list != NULL) { SetEvent (_dbus_list_pop_first (&cond->list)); /* Avoid live lock by pushing the waiter to the mutex lock instruction, which is fair. If we don't do this, we could acquire the condition variable again before the waiter has a chance itself, leading to starvation. */ Sleep (0); } LeaveCriticalSection (&cond->lock); } dbus_bool_t _dbus_threads_init_platform_specific (void) { /* We reuse this over several generations, because we can't * free the events once they are in use */ if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) { dbus_cond_event_tls = TlsAlloc (); if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) return FALSE; } return TRUE; } void _dbus_threads_lock_platform_specific (void) { _dbus_assert (global_init_done); EnterCriticalSection (&init_lock); } void _dbus_threads_unlock_platform_specific (void) { _dbus_assert (global_init_done); LeaveCriticalSection (&init_lock); } dbus-1.10.6/dbus/dbus-sysdeps-win.h0000644000175000017500000000626012624705346017101 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2005 Novell, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SYSDEPS_WIN_H #define DBUS_SYSDEPS_WIN_H extern void *_dbus_win_get_dll_hmodule (void); #define WIN32_LEAN_AND_MEAN #include "dbus-hash.h" #include "dbus-string.h" #include #include #include #undef interface #define DBUS_CONSOLE_DIR "/var/run/console/" void _dbus_win_set_errno (int err); DBUS_PRIVATE_EXPORT const char* _dbus_win_error_from_last_error (void); dbus_bool_t _dbus_win_startup_winsock (void); void _dbus_win_warn_win_error (const char *message, unsigned long code); DBUS_PRIVATE_EXPORT char * _dbus_win_error_string (int error_number); DBUS_PRIVATE_EXPORT void _dbus_win_free_error_string (char *string); extern const char* _dbus_lm_strerror (int error_number); dbus_bool_t _dbus_win_account_to_sid (const wchar_t *waccount, void **ppsid, DBusError *error); dbus_bool_t _dbus_win32_sid_to_name_and_domain (dbus_uid_t uid, wchar_t **wname, wchar_t **wdomain, DBusError *error); /* Don't define DBUS_CONSOLE_DIR on Win32 */ wchar_t *_dbus_win_utf8_to_utf16 (const char *str, DBusError *error); char *_dbus_win_utf16_to_utf8 (const wchar_t *str, DBusError *error); DBUS_PRIVATE_EXPORT void _dbus_win_set_error_from_win_error (DBusError *error, int code); dbus_bool_t _dbus_win_sid_to_name_and_domain (dbus_uid_t uid, wchar_t **wname, wchar_t **wdomain, DBusError *error); dbus_bool_t _dbus_file_exists (const char *filename); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_get_install_root(char *prefix, int len); void _dbus_threads_windows_init_global (void); void _dbus_threads_windows_ensure_ctor_linked (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_getsid(char **sid, dbus_pid_t process_id); #endif /** @} end of sysdeps-win.h */ dbus-1.10.6/dbus/dbus-sysdeps-win.c0000644000175000017500000027754212624705346017111 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2005 Novell, Inc. * Copyright (C) 2006 Peter Kümmel * Copyright (C) 2006 Christian Ehrlicher * Copyright (C) 2006-2013 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #define STRSAFE_NO_DEPRECATE #ifndef DBUS_WINCE #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #endif #include "dbus-internals.h" #include "dbus-sha.h" #include "dbus-sysdeps.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-win.h" #include "dbus-protocol.h" #include "dbus-hash.h" #include "dbus-sockets-win.h" #include "dbus-list.h" #include "dbus-nonce.h" #include "dbus-credentials.h" #include #include #include /* Declarations missing in mingw's and windows sdk 7.0 headers */ extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid); extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid); #include #include #include #if HAVE_ERRNO_H #include #endif #ifndef DBUS_WINCE #include #include #include #endif #ifdef HAVE_WS2TCPIP_H /* getaddrinfo for Windows CE (and Windows). */ #include #endif #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef PROCESS_QUERY_LIMITED_INFORMATION /* MinGW32 < 4 does not define this value in its headers */ #define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) #endif typedef int socklen_t; void _dbus_win_set_errno (int err) { #ifdef DBUS_WINCE SetLastError (err); #else errno = err; #endif } static BOOL is_winxp_sp3_or_lower(); /* * _MIB_TCPROW_EX and friends are not available in system headers * and are mapped to attribute identical ...OWNER_PID typedefs. */ typedef MIB_TCPROW_OWNER_PID _MIB_TCPROW_EX; typedef MIB_TCPTABLE_OWNER_PID MIB_TCPTABLE_EX; typedef PMIB_TCPTABLE_OWNER_PID PMIB_TCPTABLE_EX; typedef DWORD (WINAPI *ProcAllocateAndGetTcpExtTableFromStack)(PMIB_TCPTABLE_EX*,BOOL,HANDLE,DWORD,DWORD); static ProcAllocateAndGetTcpExtTableFromStack lpfnAllocateAndGetTcpExTableFromStack = NULL; /** * AllocateAndGetTcpExTableFromStack() is undocumented and not exported, * but is the only way to do this in older XP versions. * @return true if the procedures could be loaded */ static BOOL load_ex_ip_helper_procedures(void) { HMODULE hModule = LoadLibrary ("iphlpapi.dll"); if (hModule == NULL) { _dbus_verbose ("could not load iphlpapi.dll\n"); return FALSE; } lpfnAllocateAndGetTcpExTableFromStack = (ProcAllocateAndGetTcpExtTableFromStack)GetProcAddress (hModule, "AllocateAndGetTcpExTableFromStack"); if (lpfnAllocateAndGetTcpExTableFromStack == NULL) { _dbus_verbose ("could not find function AllocateAndGetTcpExTableFromStack in iphlpapi.dll\n"); return FALSE; } return TRUE; } /** * get pid from localhost tcp connection using peer_port * This function is available on WinXP >= SP3 * @param peer_port peers tcp port * @return process id or 0 if connection has not been found */ static dbus_pid_t get_pid_from_extended_tcp_table(int peer_port) { dbus_pid_t result; DWORD errorCode, size = 0, i; MIB_TCPTABLE_OWNER_PID *tcp_table; if ((errorCode = GetExtendedTcpTable (NULL, &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) == ERROR_INSUFFICIENT_BUFFER) { tcp_table = (MIB_TCPTABLE_OWNER_PID *) dbus_malloc (size); if (tcp_table == NULL) { _dbus_verbose ("Error allocating memory\n"); return 0; } } else { _dbus_win_warn_win_error ("unexpected error returned from GetExtendedTcpTable", errorCode); return 0; } if ((errorCode = GetExtendedTcpTable (tcp_table, &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) { _dbus_verbose ("Error fetching tcp table %d\n", (int)errorCode); dbus_free (tcp_table); return 0; } result = 0; for (i = 0; i < tcp_table->dwNumEntries; i++) { MIB_TCPROW_OWNER_PID *p = &tcp_table->table[i]; int local_address = ntohl (p->dwLocalAddr); int local_port = ntohs (p->dwLocalPort); if (p->dwState == MIB_TCP_STATE_ESTAB && local_address == INADDR_LOOPBACK && local_port == peer_port) result = p->dwOwningPid; } dbus_free (tcp_table); _dbus_verbose ("got pid %lu\n", result); return result; } /** * get pid from localhost tcp connection using peer_port * This function is available on all WinXP versions, but * not in wine (at least version <= 1.6.0) * @param peer_port peers tcp port * @return process id or 0 if connection has not been found */ static dbus_pid_t get_pid_from_tcp_ex_table(int peer_port) { dbus_pid_t result; DWORD errorCode, i; PMIB_TCPTABLE_EX tcp_table = NULL; if (!load_ex_ip_helper_procedures ()) { _dbus_verbose ("Error not been able to load iphelper procedures\n"); return 0; } errorCode = lpfnAllocateAndGetTcpExTableFromStack (&tcp_table, TRUE, GetProcessHeap(), 0, 2); if (errorCode != NO_ERROR) { _dbus_verbose ("Error not been able to call AllocateAndGetTcpExTableFromStack()\n"); return 0; } result = 0; for (i = 0; i < tcp_table->dwNumEntries; i++) { _MIB_TCPROW_EX *p = &tcp_table->table[i]; int local_port = ntohs (p->dwLocalPort); int local_address = ntohl (p->dwLocalAddr); if (local_address == INADDR_LOOPBACK && local_port == peer_port) { result = p->dwOwningPid; break; } } HeapFree (GetProcessHeap(), 0, tcp_table); _dbus_verbose ("got pid %lu\n", result); return result; } /** * @brief return peer process id from tcp handle for localhost connections * @param handle tcp socket descriptor * @return process id or 0 in case the process id could not be fetched */ static dbus_pid_t _dbus_get_peer_pid_from_tcp_handle (int handle) { struct sockaddr_storage addr; socklen_t len = sizeof (addr); int peer_port; dbus_pid_t result; dbus_bool_t is_localhost = FALSE; getpeername (handle, (struct sockaddr *) &addr, &len); if (addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *) &addr; peer_port = ntohs (s->sin_port); is_localhost = (ntohl (s->sin_addr.s_addr) == INADDR_LOOPBACK); } else if (addr.ss_family == AF_INET6) { _dbus_verbose ("FIXME [61922]: IPV6 support not working on windows\n"); return 0; /* struct sockaddr_in6 *s = (struct sockaddr_in6 * )&addr; peer_port = ntohs (s->sin6_port); is_localhost = (memcmp(s->sin6_addr.s6_addr, in6addr_loopback.s6_addr, 16) == 0); _dbus_verbose ("IPV6 %08x %08x\n", s->sin6_addr.s6_addr, in6addr_loopback.s6_addr); */ } else { _dbus_verbose ("no idea what address family %d is\n", addr.ss_family); return 0; } if (!is_localhost) { _dbus_verbose ("could not fetch process id from remote process\n"); return 0; } if (peer_port == 0) { _dbus_verbose ("Error not been able to fetch tcp peer port from connection\n"); return 0; } _dbus_verbose ("trying to get peer's pid\n"); result = get_pid_from_extended_tcp_table (peer_port); if (result > 0) return result; result = get_pid_from_tcp_ex_table (peer_port); return result; } /* Convert GetLastError() to a dbus error. */ const char* _dbus_win_error_from_last_error (void) { switch (GetLastError()) { case 0: return DBUS_ERROR_FAILED; case ERROR_NO_MORE_FILES: case ERROR_TOO_MANY_OPEN_FILES: return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */ case ERROR_ACCESS_DENIED: case ERROR_CANNOT_MAKE: return DBUS_ERROR_ACCESS_DENIED; case ERROR_NOT_ENOUGH_MEMORY: return DBUS_ERROR_NO_MEMORY; case ERROR_FILE_EXISTS: return DBUS_ERROR_FILE_EXISTS; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return DBUS_ERROR_FILE_NOT_FOUND; } return DBUS_ERROR_FAILED; } char* _dbus_win_error_string (int error_number) { char *msg; FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_number, 0, (LPSTR) &msg, 0, NULL); if (msg[strlen (msg) - 1] == '\n') msg[strlen (msg) - 1] = '\0'; if (msg[strlen (msg) - 1] == '\r') msg[strlen (msg) - 1] = '\0'; return msg; } void _dbus_win_free_error_string (char *string) { LocalFree (string); } /** * Socket interface * */ /** * Thin wrapper around the read() system call that appends * the data it reads to the DBusString buffer. It appends * up to the given count, and returns the same value * and same errno as read(). The only exception is that * _dbus_read_socket() handles EINTR for you. * _dbus_read_socket() can return ENOMEM, even though * regular UNIX read doesn't. * * @param fd the file descriptor to read from * @param buffer the buffer to append data to * @param count the amount of data to read * @returns the number of bytes read or -1 */ int _dbus_read_socket (DBusSocket fd, DBusString *buffer, int count) { int bytes_read; int start; char *data; _dbus_assert (count >= 0); start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) { _dbus_win_set_errno (ENOMEM); return -1; } data = _dbus_string_get_data_len (buffer, start, count); again: _dbus_verbose ("recv: count=%d fd=%Iu\n", count, fd.sock); bytes_read = recv (fd.sock, data, count, 0); if (bytes_read == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO(); _dbus_verbose ("recv: failed: %s (%d)\n", _dbus_strerror (errno), errno); bytes_read = -1; } else _dbus_verbose ("recv: = %d\n", bytes_read); if (bytes_read < 0) { if (errno == EINTR) goto again; else { /* put length back (note that this doesn't actually realloc anything) */ _dbus_string_set_length (buffer, start); return -1; } } else { /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); #if 0 if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif return bytes_read; } } /** * Thin wrapper around the write() system call that writes a part of a * DBusString and handles EINTR for you. * * @param fd the file descriptor to write * @param buffer the buffer to write data from * @param start the first byte in the buffer to write * @param len the number of bytes to try to write * @returns the number of bytes written or -1 on error */ int _dbus_write_socket (DBusSocket fd, const DBusString *buffer, int start, int len) { const char *data; int bytes_written; data = _dbus_string_get_const_data_len (buffer, start, len); again: _dbus_verbose ("send: len=%d fd=%Iu\n", len, fd.sock); bytes_written = send (fd.sock, data, len, 0); if (bytes_written == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO(); _dbus_verbose ("send: failed: %s\n", _dbus_strerror_from_errno ()); bytes_written = -1; } else _dbus_verbose ("send: = %d\n", bytes_written); if (bytes_written < 0 && errno == EINTR) goto again; #if 0 if (bytes_written > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_written); #endif return bytes_written; } /** * Closes a file descriptor. * * @param fd the file descriptor * @param error error object * @returns #FALSE if error set */ dbus_bool_t _dbus_close_socket (DBusSocket fd, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: if (closesocket (fd.sock) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); if (errno == EINTR) goto again; dbus_set_error (error, _dbus_error_from_errno (errno), "Could not close socket: socket=%Iu, , %s", fd.sock, _dbus_strerror_from_errno ()); return FALSE; } _dbus_verbose ("_dbus_close_socket: socket=%Iu, \n", fd.sock); return TRUE; } /** * Sets the file descriptor to be close * on exec. Should be called for all file * descriptors in D-Bus code. * * @param handle the Windows HANDLE (a SOCKET is also OK) */ static void _dbus_win_handle_set_close_on_exec (HANDLE handle) { if ( !SetHandleInformation( (HANDLE) handle, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, 0 /*disable both flags*/ ) ) { _dbus_win_warn_win_error ("Disabling socket handle inheritance failed:", GetLastError()); } } /** * Sets a file descriptor to be nonblocking. * * @param handle the file descriptor. * @param error address of error location. * @returns #TRUE on success. */ dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket handle, DBusError *error) { u_long one = 1; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (ioctlsocket (handle.sock, FIONBIO, &one) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set socket %Iu to nonblocking: %s", handle.sock, _dbus_strerror_from_errno ()); return FALSE; } return TRUE; } /** * Like _dbus_write() but will use writev() if possible * to write both buffers in sequence. The return value * is the number of bytes written in the first buffer, * plus the number written in the second. If the first * buffer is written successfully and an error occurs * writing the second, the number of bytes in the first * is returned (i.e. the error is ignored), on systems that * don't have writev. Handles EINTR for you. * The second buffer may be #NULL. * * @param fd the file descriptor * @param buffer1 first buffer * @param start1 first byte to write in first buffer * @param len1 number of bytes to write from first buffer * @param buffer2 second buffer, or #NULL * @param start2 first byte to write in second buffer * @param len2 number of bytes to write in second buffer * @returns total bytes written from both buffers, or -1 on error */ int _dbus_write_socket_two (DBusSocket fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2) { WSABUF vectors[2]; const char *data1; const char *data2; int rc; DWORD bytes_written; _dbus_assert (buffer1 != NULL); _dbus_assert (start1 >= 0); _dbus_assert (start2 >= 0); _dbus_assert (len1 >= 0); _dbus_assert (len2 >= 0); data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); if (buffer2 != NULL) data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); else { data2 = NULL; start2 = 0; len2 = 0; } vectors[0].buf = (char*) data1; vectors[0].len = len1; vectors[1].buf = (char*) data2; vectors[1].len = len2; again: _dbus_verbose ("WSASend: len1+2=%d+%d fd=%Iu\n", len1, len2, fd.sock); rc = WSASend (fd.sock, vectors, data2 ? 2 : 1, &bytes_written, 0, NULL, NULL); if (rc == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror_from_errno ()); bytes_written = -1; } else _dbus_verbose ("WSASend: = %ld\n", bytes_written); if (bytes_written < 0 && errno == EINTR) goto again; return bytes_written; } #if 0 /** * Opens the client side of a Windows named pipe. The connection D-BUS * file descriptor index is returned. It is set up as nonblocking. * * @param path the path to named pipe socket * @param error return location for error code * @returns connection D-BUS file descriptor or -1 on error */ int _dbus_connect_named_pipe (const char *path, DBusError *error) { _dbus_assert_not_reached ("not implemented"); } #endif /** * @returns #FALSE if no memory */ dbus_bool_t _dbus_win_startup_winsock (void) { /* Straight from MSDN, deuglified */ /* Protected by _DBUS_LOCK_sysdeps */ static dbus_bool_t beenhere = FALSE; WORD wVersionRequested; WSADATA wsaData; int err; if (!_DBUS_LOCK (sysdeps)) return FALSE; if (beenhere) goto out; wVersionRequested = MAKEWORD (2, 0); err = WSAStartup (wVersionRequested, &wsaData); if (err != 0) { _dbus_assert_not_reached ("Could not initialize WinSock"); _dbus_abort (); } /* Confirm that the WinSock DLL supports 2.0. Note that if the DLL * supports versions greater than 2.0 in addition to 2.0, it will * still return 2.0 in wVersion since that is the version we * requested. */ if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 0) { _dbus_assert_not_reached ("No usable WinSock found"); _dbus_abort (); } beenhere = TRUE; out: _DBUS_UNLOCK (sysdeps); return TRUE; } /************************************************************************ UTF / string code ************************************************************************/ /** * Measure the message length without terminating nul */ int _dbus_printf_string_upper_bound (const char *format, va_list args) { /* MSVCRT's vsnprintf semantics are a bit different */ char buf[1024]; int bufsize; int len; va_list args_copy; bufsize = sizeof (buf); DBUS_VA_COPY (args_copy, args); len = _vsnprintf (buf, bufsize - 1, format, args_copy); va_end (args_copy); while (len == -1) /* try again */ { char *p; bufsize *= 2; p = malloc (bufsize); if (p == NULL) return -1; DBUS_VA_COPY (args_copy, args); len = _vsnprintf (p, bufsize - 1, format, args_copy); va_end (args_copy); free (p); } return len; } /** * Returns the UTF-16 form of a UTF-8 string. The result should be * freed with dbus_free() when no longer needed. * * @param str the UTF-8 string * @param error return location for error code */ wchar_t * _dbus_win_utf8_to_utf16 (const char *str, DBusError *error) { DBusString s; int n; wchar_t *retval; _dbus_string_init_const (&s, str); if (!_dbus_string_validate_utf8 (&s, 0, _dbus_string_get_length (&s))) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid UTF-8"); return NULL; } n = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0); if (n == 0) { _dbus_win_set_error_from_win_error (error, GetLastError ()); return NULL; } retval = dbus_new (wchar_t, n); if (!retval) { _DBUS_SET_OOM (error); return NULL; } if (MultiByteToWideChar (CP_UTF8, 0, str, -1, retval, n) != n) { dbus_free (retval); dbus_set_error_const (error, DBUS_ERROR_FAILED, "MultiByteToWideChar inconsistency"); return NULL; } return retval; } /** * Returns the UTF-8 form of a UTF-16 string. The result should be * freed with dbus_free() when no longer needed. * * @param str the UTF-16 string * @param error return location for error code */ char * _dbus_win_utf16_to_utf8 (const wchar_t *str, DBusError *error) { int n; char *retval; n = WideCharToMultiByte (CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); if (n == 0) { _dbus_win_set_error_from_win_error (error, GetLastError ()); return NULL; } retval = dbus_malloc (n); if (!retval) { _DBUS_SET_OOM (error); return NULL; } if (WideCharToMultiByte (CP_UTF8, 0, str, -1, retval, n, NULL, NULL) != n) { dbus_free (retval); dbus_set_error_const (error, DBUS_ERROR_FAILED, "WideCharToMultiByte inconsistency"); return NULL; } return retval; } /************************************************************************ ************************************************************************/ dbus_bool_t _dbus_win_account_to_sid (const wchar_t *waccount, void **ppsid, DBusError *error) { dbus_bool_t retval = FALSE; DWORD sid_length, wdomain_length; SID_NAME_USE use; wchar_t *wdomain; *ppsid = NULL; sid_length = 0; wdomain_length = 0; if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length, NULL, &wdomain_length, &use) && GetLastError () != ERROR_INSUFFICIENT_BUFFER) { _dbus_win_set_error_from_win_error (error, GetLastError ()); return FALSE; } *ppsid = dbus_malloc (sid_length); if (!*ppsid) { _DBUS_SET_OOM (error); return FALSE; } wdomain = dbus_new (wchar_t, wdomain_length); if (!wdomain) { _DBUS_SET_OOM (error); goto out1; } if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length, wdomain, &wdomain_length, &use)) { _dbus_win_set_error_from_win_error (error, GetLastError ()); goto out2; } if (!IsValidSid ((PSID) *ppsid)) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); goto out2; } retval = TRUE; out2: dbus_free (wdomain); out1: if (!retval) { dbus_free (*ppsid); *ppsid = NULL; } return retval; } /** @} end of sysdeps-win */ /** * The only reason this is separate from _dbus_getpid() is to allow it * on Windows for logging but not for other purposes. * * @returns process ID to put in log messages */ unsigned long _dbus_pid_for_log (void) { return _dbus_getpid (); } #ifndef DBUS_WINCE static BOOL is_winxp_sp3_or_lower() { OSVERSIONINFOEX osvi; DWORDLONG dwlConditionMask = 0; int op=VER_LESS_EQUAL; // Initialize the OSVERSIONINFOEX structure. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osvi.dwMajorVersion = 5; osvi.dwMinorVersion = 1; osvi.wServicePackMajor = 3; osvi.wServicePackMinor = 0; // Initialize the condition mask. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op ); VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op ); VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op ); VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op ); // Perform the test. return VerifyVersionInfo( &osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask); } /** Gets our SID * @param sid points to sid buffer, need to be freed with LocalFree() * @param process_id the process id for which the sid should be returned (use 0 for current process) * @returns process sid */ dbus_bool_t _dbus_getsid(char **sid, dbus_pid_t process_id) { HANDLE process_token = INVALID_HANDLE_VALUE; TOKEN_USER *token_user = NULL; DWORD n; PSID psid; int retval = FALSE; HANDLE process_handle; if (process_id == 0) process_handle = GetCurrentProcess(); else if (is_winxp_sp3_or_lower()) process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id); else process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id); if (!OpenProcessToken (process_handle, TOKEN_QUERY, &process_token)) { _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ()); goto failed; } if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n) && GetLastError () != ERROR_INSUFFICIENT_BUFFER) || (token_user = alloca (n)) == NULL || !GetTokenInformation (process_token, TokenUser, token_user, n, &n)) { _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ()); goto failed; } psid = token_user->User.Sid; if (!IsValidSid (psid)) { _dbus_verbose("%s invalid sid\n",__FUNCTION__); goto failed; } if (!ConvertSidToStringSidA (psid, sid)) { _dbus_verbose("%s invalid sid\n",__FUNCTION__); goto failed; } //okay: retval = TRUE; failed: CloseHandle (process_handle); if (process_token != INVALID_HANDLE_VALUE) CloseHandle (process_token); _dbus_verbose("_dbus_getsid() got '%s' and returns %d\n", *sid, retval); return retval; } #endif /************************************************************************ pipes ************************************************************************/ /** * Creates pair of connect sockets (as in socketpair()). * Sets both ends of the pair nonblocking. * * Marks both file descriptors as close-on-exec * * @param fd1 return location for one end * @param fd2 return location for the other end * @param blocking #TRUE if pair should be blocking * @param error error return * @returns #FALSE on failure (if error is set) */ dbus_bool_t _dbus_socketpair (DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error) { SOCKET temp, socket1 = -1, socket2 = -1; struct sockaddr_in saddr; int len; u_long arg; if (!_dbus_win_startup_winsock ()) { _DBUS_SET_OOM (error); return FALSE; } temp = socket (AF_INET, SOCK_STREAM, 0); if (temp == INVALID_SOCKET) { DBUS_SOCKET_SET_ERRNO (); goto out0; } _DBUS_ZERO (saddr); saddr.sin_family = AF_INET; saddr.sin_port = 0; saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out0; } if (listen (temp, 1) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out0; } len = sizeof (saddr); if (getsockname (temp, (struct sockaddr *)&saddr, &len) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out0; } socket1 = socket (AF_INET, SOCK_STREAM, 0); if (socket1 == INVALID_SOCKET) { DBUS_SOCKET_SET_ERRNO (); goto out0; } if (connect (socket1, (struct sockaddr *)&saddr, len) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out1; } socket2 = accept (temp, (struct sockaddr *) &saddr, &len); if (socket2 == INVALID_SOCKET) { DBUS_SOCKET_SET_ERRNO (); goto out1; } if (!blocking) { arg = 1; if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out2; } arg = 1; if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); goto out2; } } fd1->sock = socket1; fd2->sock = socket2; _dbus_verbose ("full-duplex pipe %Iu:%Iu <-> %Iu:%Iu\n", fd1->sock, socket1, fd2->sock, socket2); closesocket (temp); return TRUE; out2: closesocket (socket2); out1: closesocket (socket1); out0: closesocket (temp); dbus_set_error (error, _dbus_error_from_errno (errno), "Could not setup socket pair: %s", _dbus_strerror_from_errno ()); return FALSE; } /** * Wrapper for poll(). * * @param fds the file descriptors to poll * @param n_fds number of descriptors in the array * @param timeout_milliseconds timeout or -1 for infinite * @returns numbers of fds with revents, or <0 on error */ int _dbus_poll (DBusPollFD *fds, int n_fds, int timeout_milliseconds) { #define USE_CHRIS_IMPL 0 #if USE_CHRIS_IMPL #define DBUS_POLL_CHAR_BUFFER_SIZE 2000 char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; char *msgp; int ret = 0; int i; struct timeval tv; int ready; #define DBUS_STACK_WSAEVENTS 256 WSAEVENT eventsOnStack[DBUS_STACK_WSAEVENTS]; WSAEVENT *pEvents = NULL; if (n_fds > DBUS_STACK_WSAEVENTS) pEvents = calloc(sizeof(WSAEVENT), n_fds); else pEvents = eventsOnStack; #ifdef DBUS_ENABLE_VERBOSE_MODE msgp = msg; msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds); for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; if (fdp->events & _DBUS_POLLIN) msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock); if (fdp->events & _DBUS_POLLOUT) msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock); msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock); // FIXME: more robust code for long msg // create on heap when msg[] becomes too small if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) { _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); } } msgp += sprintf (msgp, "\n"); _dbus_verbose ("%s",msg); #endif for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; WSAEVENT ev; long lNetworkEvents = FD_OOB; ev = WSACreateEvent(); if (fdp->events & _DBUS_POLLIN) lNetworkEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; if (fdp->events & _DBUS_POLLOUT) lNetworkEvents |= FD_WRITE | FD_CONNECT; WSAEventSelect(fdp->fd.sock, ev, lNetworkEvents); pEvents[i] = ev; } ready = WSAWaitForMultipleEvents (n_fds, pEvents, FALSE, timeout_milliseconds, FALSE); if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) { DBUS_SOCKET_SET_ERRNO (); if (errno != WSAEWOULDBLOCK) _dbus_verbose ("WSAWaitForMultipleEvents: failed: %s\n", _dbus_strerror_from_errno ()); ret = -1; } else if (ready == WSA_WAIT_TIMEOUT) { _dbus_verbose ("WSAWaitForMultipleEvents: WSA_WAIT_TIMEOUT\n"); ret = 0; } else if (ready >= WSA_WAIT_EVENT_0 && ready < (int)(WSA_WAIT_EVENT_0 + n_fds)) { msgp = msg; msgp += sprintf (msgp, "WSAWaitForMultipleEvents: =%d\n\t", ready); for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; WSANETWORKEVENTS ne; fdp->revents = 0; WSAEnumNetworkEvents(fdp->fd.sock, pEvents[i], &ne); if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) fdp->revents |= _DBUS_POLLIN; if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) fdp->revents |= _DBUS_POLLOUT; if (ne.lNetworkEvents & (FD_OOB)) fdp->revents |= _DBUS_POLLERR; if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock); if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock); if (ne.lNetworkEvents & (FD_OOB)) msgp += sprintf (msgp, "E:%Iu ", fdp->fd.sock); msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents); if(ne.lNetworkEvents) ret++; WSAEventSelect(fdp->fd.sock, pEvents[i], 0); } msgp += sprintf (msgp, "\n"); _dbus_verbose ("%s",msg); } else { _dbus_verbose ("WSAWaitForMultipleEvents: failed for unknown reason!"); ret = -1; } for(i = 0; i < n_fds; i++) { WSACloseEvent(pEvents[i]); } if (n_fds > DBUS_STACK_WSAEVENTS) free(pEvents); return ret; #else /* USE_CHRIS_IMPL */ #define DBUS_POLL_CHAR_BUFFER_SIZE 2000 char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; char *msgp; fd_set read_set, write_set, err_set; SOCKET max_fd = 0; int i; struct timeval tv; int ready; FD_ZERO (&read_set); FD_ZERO (&write_set); FD_ZERO (&err_set); #ifdef DBUS_ENABLE_VERBOSE_MODE msgp = msg; msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds); for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; if (fdp->events & _DBUS_POLLIN) msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock); if (fdp->events & _DBUS_POLLOUT) msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock); msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock); // FIXME: more robust code for long msg // create on heap when msg[] becomes too small if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) { _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); } } msgp += sprintf (msgp, "\n"); _dbus_verbose ("%s",msg); #endif for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; if (fdp->events & _DBUS_POLLIN) FD_SET (fdp->fd.sock, &read_set); if (fdp->events & _DBUS_POLLOUT) FD_SET (fdp->fd.sock, &write_set); FD_SET (fdp->fd.sock, &err_set); max_fd = MAX (max_fd, fdp->fd.sock); } // Avoid random lockups with send(), for lack of a better solution so far tv.tv_sec = timeout_milliseconds < 0 ? 1 : timeout_milliseconds / 1000; tv.tv_usec = timeout_milliseconds < 0 ? 0 : (timeout_milliseconds % 1000) * 1000; ready = select (max_fd + 1, &read_set, &write_set, &err_set, &tv); if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) { DBUS_SOCKET_SET_ERRNO (); if (errno != WSAEWOULDBLOCK) _dbus_verbose ("select: failed: %s\n", _dbus_strerror_from_errno ()); } else if (ready == 0) _dbus_verbose ("select: = 0\n"); else if (ready > 0) { #ifdef DBUS_ENABLE_VERBOSE_MODE msgp = msg; msgp += sprintf (msgp, "select: = %d:\n\t", ready); for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; if (FD_ISSET (fdp->fd.sock, &read_set)) msgp += sprintf (msgp, "R:%Iu ", fdp->fd.sock); if (FD_ISSET (fdp->fd.sock, &write_set)) msgp += sprintf (msgp, "W:%Iu ", fdp->fd.sock); if (FD_ISSET (fdp->fd.sock, &err_set)) msgp += sprintf (msgp, "E:%Iu\n\t", fdp->fd.sock); } msgp += sprintf (msgp, "\n"); _dbus_verbose ("%s",msg); #endif for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; fdp->revents = 0; if (FD_ISSET (fdp->fd.sock, &read_set)) fdp->revents |= _DBUS_POLLIN; if (FD_ISSET (fdp->fd.sock, &write_set)) fdp->revents |= _DBUS_POLLOUT; if (FD_ISSET (fdp->fd.sock, &err_set)) fdp->revents |= _DBUS_POLLERR; } } return ready; #endif /* USE_CHRIS_IMPL */ } /****************************************************************************** Original CVS version of dbus-sysdeps.c ******************************************************************************/ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2005 Novell, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * Exit the process, returning the given value. * * @param code the exit code */ void _dbus_exit (int code) { _exit (code); } /** * Creates a socket and connects to a socket at the given host * and port. The connection fd is returned, and is set up as * nonblocking. * * @param host the host name to connect to * @param port the port to connect to * @param family the address family to listen on, NULL for all * @param error return location for error code * @returns connection file descriptor or -1 on error */ DBusSocket _dbus_connect_tcp_socket (const char *host, const char *port, const char *family, DBusError *error) { return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error); } DBusSocket _dbus_connect_tcp_socket_with_nonce (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error) { DBusSocket fd = DBUS_SOCKET_INIT; int res; struct addrinfo hints; struct addrinfo *ai, *tmp; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_win_startup_winsock ()) { _DBUS_SET_OOM (error); return _dbus_socket_get_invalid (); } _DBUS_ZERO (hints); if (!family) hints.ai_family = AF_UNSPEC; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) hints.ai_family = AF_INET6; else { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Unknown address family %s", family); return _dbus_socket_get_invalid (); } hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG; #else hints.ai_flags = 0; #endif if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) { dbus_set_error (error, _dbus_error_from_errno (res), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host, port, _dbus_strerror(res), res); return _dbus_socket_get_invalid (); } tmp = ai; while (tmp) { if ((fd.sock = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET) { DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open socket: %s", _dbus_strerror_from_errno ()); freeaddrinfo(ai); return _dbus_socket_get_invalid (); } _DBUS_ASSERT_ERROR_IS_CLEAR(error); if (connect (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); closesocket(fd.sock); fd.sock = INVALID_SOCKET; tmp = tmp->ai_next; continue; } break; } freeaddrinfo(ai); if (!_dbus_socket_is_valid (fd)) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to connect to socket \"%s:%s\" %s", host, port, _dbus_strerror_from_errno ()); return _dbus_socket_get_invalid (); } if (noncefile != NULL) { DBusString noncefileStr; dbus_bool_t ret; if (!_dbus_string_init (&noncefileStr) || !_dbus_string_append(&noncefileStr, noncefile)) { closesocket (fd.sock); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return _dbus_socket_get_invalid (); } ret = _dbus_send_nonce (fd, &noncefileStr, error); _dbus_string_free (&noncefileStr); if (!ret) { closesocket (fd.sock); return _dbus_socket_get_invalid (); } } /* Every SOCKET is also a HANDLE. */ _dbus_win_handle_set_close_on_exec ((HANDLE) fd.sock); if (!_dbus_set_socket_nonblocking (fd, error)) { closesocket (fd.sock); return _dbus_socket_get_invalid (); } return fd; } /** * Creates a socket and binds it to the given path, then listens on * the socket. The socket is set to be nonblocking. In case of port=0 * a random free port is used and returned in the port parameter. * If inaddr_any is specified, the hostname is ignored. * * @param host the host name to listen on * @param port the port to listen on, if zero a free port will be used * @param family the address family to listen on, NULL for all * @param retport string to return the actual port listened on * @param fds_p location to store returned file descriptors * @param error return location for errors * @returns the number of listening file descriptors or -1 on error */ int _dbus_listen_tcp_socket (const char *host, const char *port, const char *family, DBusString *retport, DBusSocket **fds_p, DBusError *error) { DBusSocket *listen_fd = NULL; int nlisten_fd = 0, res, i, port_num = -1; struct addrinfo hints; struct addrinfo *ai, *tmp; // On Vista, sockaddr_gen must be a sockaddr_in6, and not a sockaddr_in6_old //That's required for family == IPv6(which is the default on Vista if family is not given) //So we use our own union instead of sockaddr_gen: typedef union { struct sockaddr Address; struct sockaddr_in AddressIn; struct sockaddr_in6 AddressIn6; } mysockaddr_gen; *fds_p = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_win_startup_winsock ()) { _DBUS_SET_OOM (error); return -1; } _DBUS_ZERO (hints); if (!family) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) hints.ai_family = AF_INET6; else { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Unknown address family %s", family); return -1; } hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; #else hints.ai_flags = AI_PASSIVE; #endif redo_lookup_with_port: if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) { dbus_set_error (error, _dbus_error_from_errno (res), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host ? host : "*", port, _dbus_strerror(res), res); return -1; } tmp = ai; while (tmp) { DBusSocket fd = DBUS_SOCKET_INIT, *newlisten_fd; if ((fd.sock = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET) { DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open socket: %s", _dbus_strerror_from_errno ()); goto failed; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); if (bind (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); closesocket (fd.sock); if (errno == WSAEADDRINUSE) { /* Calling this function with port=0 tries to * bind the same port twice, so we should * ignore the second bind. */ tmp = tmp->ai_next; continue; } dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to bind socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror_from_errno ()); goto failed; } if (listen (fd.sock, 30 /* backlog */) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to listen on socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror_from_errno ()); closesocket (fd.sock); goto failed; } newlisten_fd = dbus_realloc(listen_fd, sizeof(DBusSocket)*(nlisten_fd+1)); if (!newlisten_fd) { closesocket (fd.sock); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Failed to allocate file handle array"); goto failed; } listen_fd = newlisten_fd; listen_fd[nlisten_fd] = fd; nlisten_fd++; if (!_dbus_string_get_length(retport)) { /* If the user didn't specify a port, or used 0, then the kernel chooses a port. After the first address is bound to, we need to force all remaining addresses to use the same port */ if (!port || !strcmp(port, "0")) { mysockaddr_gen addr; socklen_t addrlen = sizeof(addr); char portbuf[NI_MAXSERV]; if (getsockname(fd.sock, &addr.Address, &addrlen) == SOCKET_ERROR || (res = getnameinfo (&addr.Address, addrlen, NULL, 0, portbuf, sizeof(portbuf), NI_NUMERICSERV)) != 0) { DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to resolve port \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror_from_errno()); goto failed; } if (!_dbus_string_append(retport, portbuf)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } /* Release current address list & redo lookup */ port = _dbus_string_get_const_data(retport); freeaddrinfo(ai); goto redo_lookup_with_port; } else { if (!_dbus_string_append(retport, port)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } } } tmp = tmp->ai_next; } freeaddrinfo(ai); ai = NULL; if (!nlisten_fd) { _dbus_win_set_errno (WSAEADDRINUSE); dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to bind socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror_from_errno ()); return -1; } sscanf(_dbus_string_get_const_data(retport), "%d", &port_num); for (i = 0 ; i < nlisten_fd ; i++) { _dbus_win_handle_set_close_on_exec ((HANDLE) listen_fd[i].sock); if (!_dbus_set_socket_nonblocking (listen_fd[i], error)) { goto failed; } } *fds_p = listen_fd; return nlisten_fd; failed: if (ai) freeaddrinfo(ai); for (i = 0 ; i < nlisten_fd ; i++) closesocket (listen_fd[i].sock); dbus_free(listen_fd); return -1; } /** * Accepts a connection on a listening socket. * Handles EINTR for you. * * @param listen_fd the listen file descriptor * @returns the connection fd of the client, or -1 on error */ DBusSocket _dbus_accept (DBusSocket listen_fd) { DBusSocket client_fd; retry: client_fd.sock = accept (listen_fd.sock, NULL, NULL); if (!_dbus_socket_is_valid (client_fd)) { DBUS_SOCKET_SET_ERRNO (); if (errno == EINTR) goto retry; } _dbus_verbose ("client fd %Iu accepted\n", client_fd.sock); return client_fd; } dbus_bool_t _dbus_send_credentials_socket (DBusSocket handle, DBusError *error) { /* FIXME: for the session bus credentials shouldn't matter (?), but * for the system bus they are presumably essential. A rough outline * of a way to implement the credential transfer would be this: * * client waits to *read* a byte. * * server creates a named pipe with a random name, sends a byte * contining its length, and its name. * * client reads the name, connects to it (using Win32 API). * * server waits for connection to the named pipe, then calls * ImpersonateNamedPipeClient(), notes its now-current credentials, * calls RevertToSelf(), closes its handles to the named pipe, and * is done. (Maybe there is some other way to get the SID of a named * pipe client without having to use impersonation?) * * client closes its handles and is done. * * Ralf: Why not sending credentials over the given this connection ? * Using named pipes makes it impossible to be connected from a unix client. * */ int bytes_written; DBusString buf; _dbus_string_init_const_len (&buf, "\0", 1); again: bytes_written = _dbus_write_socket (handle, &buf, 0, 1 ); if (bytes_written < 0 && errno == EINTR) goto again; if (bytes_written < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to write credentials byte: %s", _dbus_strerror_from_errno ()); return FALSE; } else if (bytes_written == 0) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "wrote zero bytes writing credentials byte"); return FALSE; } else { _dbus_assert (bytes_written == 1); _dbus_verbose ("wrote 1 zero byte, credential sending isn't implemented yet\n"); return TRUE; } return TRUE; } /** * Reads a single byte which must be nul (an error occurs otherwise), * and reads unix credentials if available. Fills in pid/uid/gid with * -1 if no credentials are available. Return value indicates whether * a byte was read, not whether we got valid credentials. On some * systems, such as Linux, reading/writing the byte isn't actually * required, but we do it anyway just to avoid multiple codepaths. * * Fails if no byte is available, so you must select() first. * * The point of the byte is that on some systems we have to * use sendmsg()/recvmsg() to transmit credentials. * * @param handle the client file descriptor * @param credentials struct to fill with credentials of client * @param error location to store error code * @returns #TRUE on success */ dbus_bool_t _dbus_read_credentials_socket (DBusSocket handle, DBusCredentials *credentials, DBusError *error) { int bytes_read = 0; DBusString buf; char *sid = NULL; dbus_pid_t pid; int retval = FALSE; // could fail due too OOM if (_dbus_string_init (&buf)) { bytes_read = _dbus_read_socket (handle, &buf, 1 ); if (bytes_read > 0) _dbus_verbose ("got one zero byte from server\n"); _dbus_string_free (&buf); } pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock); if (pid == 0) return TRUE; _dbus_credentials_add_pid (credentials, pid); if (_dbus_getsid (&sid, pid)) { if (!_dbus_credentials_add_windows_sid (credentials, sid)) goto out; } retval = TRUE; out: if (sid) LocalFree (sid); return retval; } /** * Checks to make sure the given directory is * private to the user * * @param dir the name of the directory * @param error error return * @returns #FALSE on failure **/ dbus_bool_t _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) { /* TODO */ _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } /** * Appends the given filename to the given directory. * * @todo it might be cute to collapse multiple '/' such as "foo//" * concat "//bar" * * @param dir the directory name * @param next_component the filename * @returns #TRUE on success */ dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir, const DBusString *next_component) { dbus_bool_t dir_ends_in_slash; dbus_bool_t file_starts_with_slash; if (_dbus_string_get_length (dir) == 0 || _dbus_string_get_length (next_component) == 0) return TRUE; dir_ends_in_slash = ('/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1) || '\\' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1)); file_starts_with_slash = ('/' == _dbus_string_get_byte (next_component, 0) || '\\' == _dbus_string_get_byte (next_component, 0)); if (dir_ends_in_slash && file_starts_with_slash) { _dbus_string_shorten (dir, 1); } else if (!(dir_ends_in_slash || file_starts_with_slash)) { if (!_dbus_string_append_byte (dir, '\\')) return FALSE; } return _dbus_string_copy (next_component, 0, dir, _dbus_string_get_length (dir)); } /*---------------- DBusCredentials ----------------------------------*/ /** * Adds the credentials corresponding to the given username. * * @param credentials credentials to fill in * @param username the username * @returns #TRUE if the username existed and we got some credentials */ dbus_bool_t _dbus_credentials_add_from_user (DBusCredentials *credentials, const DBusString *username) { return _dbus_credentials_add_windows_sid (credentials, _dbus_string_get_const_data(username)); } /** * Adds the credentials of the current process to the * passed-in credentials object. * * @param credentials credentials to add to * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added */ dbus_bool_t _dbus_credentials_add_from_current_process (DBusCredentials *credentials) { dbus_bool_t retval = FALSE; char *sid = NULL; if (!_dbus_getsid(&sid, _dbus_getpid())) goto failed; if (!_dbus_credentials_add_pid (credentials, _dbus_getpid())) goto failed; if (!_dbus_credentials_add_windows_sid (credentials,sid)) goto failed; retval = TRUE; goto end; failed: retval = FALSE; end: if (sid) LocalFree(sid); return retval; } /** * Append to the string the identity we would like to have when we * authenticate, on UNIX this is the current process UID and on * Windows something else, probably a Windows SID string. No escaping * is required, that is done in dbus-auth.c. The username here * need not be anything human-readable, it can be the machine-readable * form i.e. a user id. * * @param str the string to append to * @returns #FALSE on no memory * @todo to which class belongs this */ dbus_bool_t _dbus_append_user_from_current_process (DBusString *str) { dbus_bool_t retval = FALSE; char *sid = NULL; if (!_dbus_getsid(&sid, _dbus_getpid())) return FALSE; retval = _dbus_string_append (str,sid); LocalFree(sid); return retval; } /** * Gets our process ID * @returns process ID */ dbus_pid_t _dbus_getpid (void) { return GetCurrentProcessId (); } /** Gets our Unix UID * @returns on Windows, just DBUS_UID_UNSET */ dbus_uid_t _dbus_getuid (void) { return DBUS_UID_UNSET; } /** nanoseconds in a second */ #define NANOSECONDS_PER_SECOND 1000000000 /** microseconds in a second */ #define MICROSECONDS_PER_SECOND 1000000 /** milliseconds in a second */ #define MILLISECONDS_PER_SECOND 1000 /** nanoseconds in a millisecond */ #define NANOSECONDS_PER_MILLISECOND 1000000 /** microseconds in a millisecond */ #define MICROSECONDS_PER_MILLISECOND 1000 /** * Sleeps the given number of milliseconds. * @param milliseconds number of milliseconds */ void _dbus_sleep_milliseconds (int milliseconds) { Sleep (milliseconds); } /** * Get current time, as in gettimeofday(). Never uses the monotonic * clock. * * @param tv_sec return location for number of seconds * @param tv_usec return location for number of microseconds */ void _dbus_get_real_time (long *tv_sec, long *tv_usec) { FILETIME ft; dbus_uint64_t time64; GetSystemTimeAsFileTime (&ft); memcpy (&time64, &ft, sizeof (time64)); /* Convert from 100s of nanoseconds since 1601-01-01 * to Unix epoch. Yes, this is Y2038 unsafe. */ time64 -= DBUS_INT64_CONSTANT (116444736000000000); time64 /= 10; if (tv_sec) *tv_sec = time64 / 1000000; if (tv_usec) *tv_usec = time64 % 1000000; } /** * Get current time, as in gettimeofday(). Use the monotonic clock if * available, to avoid problems when the system time changes. * * @param tv_sec return location for number of seconds * @param tv_usec return location for number of microseconds */ void _dbus_get_monotonic_time (long *tv_sec, long *tv_usec) { /* no implementation yet, fall back to wall-clock time */ _dbus_get_real_time (tv_sec, tv_usec); } /** * signal (SIGPIPE, SIG_IGN); */ void _dbus_disable_sigpipe (void) { } /** * Creates a directory; succeeds if the directory * is created or already existed. * * @param filename directory filename * @param error initialized error object * @returns #TRUE on success */ dbus_bool_t _dbus_create_directory (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (!CreateDirectoryA (filename_c, NULL)) { if (GetLastError () == ERROR_ALREADY_EXISTS) return TRUE; dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create directory %s: %s\n", filename_c, _dbus_strerror_from_errno ()); return FALSE; } else return TRUE; } /** * Generates the given number of random bytes, * using the best mechanism we can come up with. * * @param str the string * @param n_bytes the number of random bytes to append to string * @param error location to store reason for failure * @returns #TRUE on success */ dbus_bool_t _dbus_generate_random_bytes (DBusString *str, int n_bytes, DBusError *error) { int old_len; char *p; HCRYPTPROV hprov; old_len = _dbus_string_get_length (str); if (!_dbus_string_lengthen (str, n_bytes)) { _DBUS_SET_OOM (error); return FALSE; } p = _dbus_string_get_data_len (str, old_len, n_bytes); if (!CryptAcquireContext (&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { _DBUS_SET_OOM (error); return FALSE; } if (!CryptGenRandom (hprov, n_bytes, p)) { _DBUS_SET_OOM (error); CryptReleaseContext (hprov, 0); return FALSE; } CryptReleaseContext (hprov, 0); return TRUE; } /** * Gets the temporary files directory by inspecting the environment variables * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned * * @returns location of temp directory, or #NULL if no memory for locking */ const char* _dbus_get_tmpdir(void) { /* Protected by _DBUS_LOCK_sysdeps */ static const char* tmpdir = NULL; static char buf[1000]; if (!_DBUS_LOCK (sysdeps)) return NULL; if (tmpdir == NULL) { char *last_slash; if (!GetTempPathA (sizeof (buf), buf)) { _dbus_warn ("GetTempPath failed\n"); _dbus_abort (); } /* Drop terminating backslash or slash */ last_slash = _mbsrchr (buf, '\\'); if (last_slash > buf && last_slash[1] == '\0') last_slash[0] = '\0'; last_slash = _mbsrchr (buf, '/'); if (last_slash > buf && last_slash[1] == '\0') last_slash[0] = '\0'; tmpdir = buf; } _DBUS_UNLOCK (sysdeps); _dbus_assert(tmpdir != NULL); return tmpdir; } /** * Deletes the given file. * * @param filename the filename * @param error error location * * @returns #TRUE if unlink() succeeded */ dbus_bool_t _dbus_delete_file (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (DeleteFileA (filename_c) == 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to delete file %s: %s\n", filename_c, _dbus_strerror_from_errno ()); return FALSE; } else return TRUE; } #if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_ENABLE_EMBEDDED_TESTS) #if defined(_MSC_VER) || defined(DBUS_WINCE) # ifdef BACKTRACES # undef BACKTRACES # endif #else # define BACKTRACES #endif #ifdef BACKTRACES /* * Backtrace Generator * * Copyright 2004 Eric Poech * Copyright 2004 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #define DPRINTF(fmt, ...) fprintf (stderr, fmt, ##__VA_ARGS__) #ifdef _MSC_VER #define BOOL int #define __i386__ #endif //#define MAKE_FUNCPTR(f) static typeof(f) * p##f //MAKE_FUNCPTR(StackWalk); //MAKE_FUNCPTR(SymGetModuleBase); //MAKE_FUNCPTR(SymFunctionTableAccess); //MAKE_FUNCPTR(SymInitialize); //MAKE_FUNCPTR(SymGetSymFromAddr); //MAKE_FUNCPTR(SymGetModuleInfo); static BOOL (WINAPI *pStackWalk)( DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE TranslateAddress ); #ifdef _WIN64 static DWORD64 (WINAPI *pSymGetModuleBase)( HANDLE hProcess, DWORD64 dwAddr ); static PVOID (WINAPI *pSymFunctionTableAccess)( HANDLE hProcess, DWORD64 AddrBase ); #else static DWORD (WINAPI *pSymGetModuleBase)( HANDLE hProcess, DWORD dwAddr ); static PVOID (WINAPI *pSymFunctionTableAccess)( HANDLE hProcess, DWORD AddrBase ); #endif static BOOL (WINAPI *pSymInitialize)( HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess ); static BOOL (WINAPI *pSymGetSymFromAddr)( HANDLE hProcess, DWORD Address, PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol ); static BOOL (WINAPI *pSymGetModuleInfo)( HANDLE hProcess, DWORD dwAddr, PIMAGEHLP_MODULE ModuleInfo ); static DWORD (WINAPI *pSymSetOptions)( DWORD SymOptions ); static BOOL init_backtrace() { HMODULE hmodDbgHelp = LoadLibraryA("dbghelp"); /* #define GETFUNC(x) \ p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \ if (!p##x) \ { \ return FALSE; \ } */ // GETFUNC(StackWalk); // GETFUNC(SymGetModuleBase); // GETFUNC(SymFunctionTableAccess); // GETFUNC(SymInitialize); // GETFUNC(SymGetSymFromAddr); // GETFUNC(SymGetModuleInfo); #define FUNC(x) #x pStackWalk = (BOOL (WINAPI *)( DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE TranslateAddress ))GetProcAddress (hmodDbgHelp, FUNC(StackWalk)); #ifdef _WIN64 pSymGetModuleBase=(DWORD64 (WINAPI *)( HANDLE hProcess, DWORD64 dwAddr ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase)); pSymFunctionTableAccess=(PVOID (WINAPI *)( HANDLE hProcess, DWORD64 AddrBase ))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess)); #else pSymGetModuleBase=(DWORD (WINAPI *)( HANDLE hProcess, DWORD dwAddr ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase)); pSymFunctionTableAccess=(PVOID (WINAPI *)( HANDLE hProcess, DWORD AddrBase ))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess)); #endif pSymInitialize = (BOOL (WINAPI *)( HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess ))GetProcAddress (hmodDbgHelp, FUNC(SymInitialize)); pSymGetSymFromAddr = (BOOL (WINAPI *)( HANDLE hProcess, DWORD Address, PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol ))GetProcAddress (hmodDbgHelp, FUNC(SymGetSymFromAddr)); pSymGetModuleInfo = (BOOL (WINAPI *)( HANDLE hProcess, DWORD dwAddr, PIMAGEHLP_MODULE ModuleInfo ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleInfo)); pSymSetOptions = (DWORD (WINAPI *)( DWORD SymOptions ))GetProcAddress (hmodDbgHelp, FUNC(SymSetOptions)); pSymSetOptions(SYMOPT_UNDNAME); pSymInitialize(GetCurrentProcess(), NULL, TRUE); return TRUE; } static void dump_backtrace_for_thread(HANDLE hThread) { STACKFRAME sf; CONTEXT context; DWORD dwImageType; if (!pStackWalk) if (!init_backtrace()) return; /* can't use this function for current thread as GetThreadContext * doesn't support getting context from current thread */ if (hThread == GetCurrentThread()) return; DPRINTF("Backtrace:\n"); _DBUS_ZERO(context); context.ContextFlags = CONTEXT_FULL; SuspendThread(hThread); if (!GetThreadContext(hThread, &context)) { DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError()); ResumeThread(hThread); return; } _DBUS_ZERO(sf); #ifdef __i386__ sf.AddrFrame.Offset = context.Ebp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrPC.Offset = context.Eip; sf.AddrPC.Mode = AddrModeFlat; dwImageType = IMAGE_FILE_MACHINE_I386; #elif _M_X64 dwImageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = context.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Rsp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = context.Rsp; sf.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 dwImageType = IMAGE_FILE_MACHINE_IA64; sf.AddrPC.Offset = context.StIIP; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.IntSp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrBStore.Offset= context.RsBSP; sf.AddrBStore.Mode = AddrModeFlat; sf.AddrStack.Offset = context.IntSp; sf.AddrStack.Mode = AddrModeFlat; #else # error You need to fill in the STACKFRAME structure for your architecture #endif while (pStackWalk(dwImageType, GetCurrentProcess(), hThread, &sf, &context, NULL, pSymFunctionTableAccess, pSymGetModuleBase, NULL)) { BYTE buffer[256]; IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer; DWORD dwDisplacement; pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1; if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &dwDisplacement, pSymbol)) { IMAGEHLP_MODULE ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset, &ModuleInfo)) DPRINTF("1\t%p\n", (void*)sf.AddrPC.Offset); else DPRINTF("2\t%s+0x%lx\n", ModuleInfo.ImageName, sf.AddrPC.Offset - ModuleInfo.BaseOfImage); } else if (dwDisplacement) DPRINTF("3\t%s+0x%lx\n", pSymbol->Name, dwDisplacement); else DPRINTF("4\t%s\n", pSymbol->Name); } ResumeThread(hThread); } static DWORD WINAPI dump_thread_proc(LPVOID lpParameter) { dump_backtrace_for_thread((HANDLE)lpParameter); return 0; } /* cannot get valid context from current thread, so we have to execute * backtrace from another thread */ static void dump_backtrace() { HANDLE hCurrentThread; HANDLE hThread; DWORD dwThreadId; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS); hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread, 0, &dwThreadId); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hCurrentThread); } #endif #endif /* asserts or tests enabled */ #ifdef BACKTRACES void _dbus_print_backtrace(void) { init_backtrace(); dump_backtrace(); } #else void _dbus_print_backtrace(void) { _dbus_verbose (" D-Bus not compiled with backtrace support\n"); } #endif static dbus_uint32_t fromAscii(char ascii) { if(ascii >= '0' && ascii <= '9') return ascii - '0'; if(ascii >= 'A' && ascii <= 'F') return ascii - 'A' + 10; if(ascii >= 'a' && ascii <= 'f') return ascii - 'a' + 10; return 0; } dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, dbus_bool_t create_if_not_found, DBusError *error) { #ifdef DBUS_WINCE return TRUE; // TODO #else HW_PROFILE_INFOA info; char *lpc = &info.szHwProfileGuid[0]; dbus_uint32_t u; // the hw-profile guid lives long enough if(!GetCurrentHwProfileA(&info)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); // FIXME return FALSE; } // Form: {12340001-4980-1920-6788-123456789012} lpc++; // 12340001 u = ((fromAscii(lpc[0]) << 0) | (fromAscii(lpc[1]) << 4) | (fromAscii(lpc[2]) << 8) | (fromAscii(lpc[3]) << 12) | (fromAscii(lpc[4]) << 16) | (fromAscii(lpc[5]) << 20) | (fromAscii(lpc[6]) << 24) | (fromAscii(lpc[7]) << 28)); machine_id->as_uint32s[0] = u; lpc += 9; // 4980-1920 u = ((fromAscii(lpc[0]) << 0) | (fromAscii(lpc[1]) << 4) | (fromAscii(lpc[2]) << 8) | (fromAscii(lpc[3]) << 12) | (fromAscii(lpc[5]) << 16) | (fromAscii(lpc[6]) << 20) | (fromAscii(lpc[7]) << 24) | (fromAscii(lpc[8]) << 28)); machine_id->as_uint32s[1] = u; lpc += 10; // 6788-1234 u = ((fromAscii(lpc[0]) << 0) | (fromAscii(lpc[1]) << 4) | (fromAscii(lpc[2]) << 8) | (fromAscii(lpc[3]) << 12) | (fromAscii(lpc[5]) << 16) | (fromAscii(lpc[6]) << 20) | (fromAscii(lpc[7]) << 24) | (fromAscii(lpc[8]) << 28)); machine_id->as_uint32s[2] = u; lpc += 9; // 56789012 u = ((fromAscii(lpc[0]) << 0) | (fromAscii(lpc[1]) << 4) | (fromAscii(lpc[2]) << 8) | (fromAscii(lpc[3]) << 12) | (fromAscii(lpc[4]) << 16) | (fromAscii(lpc[5]) << 20) | (fromAscii(lpc[6]) << 24) | (fromAscii(lpc[7]) << 28)); machine_id->as_uint32s[3] = u; #endif return TRUE; } static HANDLE _dbus_global_lock (const char *mutexname) { HANDLE mutex; DWORD gotMutex; mutex = CreateMutexA( NULL, FALSE, mutexname ); if( !mutex ) { return FALSE; } gotMutex = WaitForSingleObject( mutex, INFINITE ); switch( gotMutex ) { case WAIT_ABANDONED: ReleaseMutex (mutex); CloseHandle (mutex); return 0; case WAIT_FAILED: case WAIT_TIMEOUT: return 0; } return mutex; } static void _dbus_global_unlock (HANDLE mutex) { ReleaseMutex (mutex); CloseHandle (mutex); } // for proper cleanup in dbus-daemon static HANDLE hDBusDaemonMutex = NULL; static HANDLE hDBusSharedMem = NULL; // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex"; // sync _dbus_get_autolaunch_address static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex"; // mutex to determine if dbus-daemon is already started (per user) static const char *cDBusDaemonMutex = "DBusDaemonMutex"; // named shm for dbus adress info (per user) static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo"; static dbus_bool_t _dbus_get_install_root_as_hash(DBusString *out) { DBusString install_path; char path[MAX_PATH*2]; int path_size = sizeof(path); if (!_dbus_get_install_root(path,path_size)) return FALSE; _dbus_string_init(&install_path); _dbus_string_append(&install_path,path); _dbus_string_init(out); _dbus_string_tolower_ascii(&install_path,0,_dbus_string_get_length(&install_path)); if (!_dbus_sha_compute (&install_path, out)) return FALSE; return TRUE; } static dbus_bool_t _dbus_get_address_string (DBusString *out, const char *basestring, const char *scope) { _dbus_string_init(out); _dbus_string_append(out,basestring); if (!scope) { return TRUE; } else if (strcmp(scope,"*install-path") == 0 // for 1.3 compatibility || strcmp(scope,"install-path") == 0) { DBusString temp; if (!_dbus_get_install_root_as_hash(&temp)) { _dbus_string_free(out); return FALSE; } _dbus_string_append(out,"-"); _dbus_string_append(out,_dbus_string_get_const_data(&temp)); _dbus_string_free(&temp); } else if (strcmp(scope,"*user") == 0) { _dbus_string_append(out,"-"); if (!_dbus_append_user_from_current_process(out)) { _dbus_string_free(out); return FALSE; } } else if (strlen(scope) > 0) { _dbus_string_append(out,"-"); _dbus_string_append(out,scope); return TRUE; } return TRUE; } static dbus_bool_t _dbus_get_shm_name (DBusString *out,const char *scope) { return _dbus_get_address_string (out,cDBusDaemonAddressInfo,scope); } static dbus_bool_t _dbus_get_mutex_name (DBusString *out,const char *scope) { return _dbus_get_address_string (out,cDBusDaemonMutex,scope); } dbus_bool_t _dbus_daemon_is_session_bus_address_published (const char *scope) { HANDLE lock; DBusString mutex_name; if (!_dbus_get_mutex_name(&mutex_name,scope)) { _dbus_string_free( &mutex_name ); return FALSE; } if (hDBusDaemonMutex) return TRUE; // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs lock = _dbus_global_lock( cUniqueDBusInitMutex ); // we use CreateMutex instead of OpenMutex because of possible race conditions, // see http://msdn.microsoft.com/en-us/library/ms684315%28VS.85%29.aspx hDBusDaemonMutex = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) ); /* The client uses mutex ownership to detect a running server, so the server should do so too. Fortunally the client deletes the mutex in the lock protected area, so checking presence will work too. */ _dbus_global_unlock( lock ); _dbus_string_free( &mutex_name ); if (hDBusDaemonMutex == NULL) return FALSE; if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(hDBusDaemonMutex); hDBusDaemonMutex = NULL; return TRUE; } // mutex wasn't created before, so return false. // We leave the mutex name allocated for later reusage // in _dbus_daemon_publish_session_bus_address. return FALSE; } dbus_bool_t _dbus_daemon_publish_session_bus_address (const char* address, const char *scope) { HANDLE lock; char *shared_addr = NULL; DBusString shm_name; DBusString mutex_name; dbus_uint64_t len; _dbus_assert (address); if (!_dbus_get_mutex_name(&mutex_name,scope)) { _dbus_string_free( &mutex_name ); return FALSE; } // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs lock = _dbus_global_lock( cUniqueDBusInitMutex ); if (!hDBusDaemonMutex) { hDBusDaemonMutex = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) ); } _dbus_string_free( &mutex_name ); // acquire the mutex if (WaitForSingleObject( hDBusDaemonMutex, 10 ) != WAIT_OBJECT_0) { _dbus_global_unlock( lock ); CloseHandle( hDBusDaemonMutex ); return FALSE; } if (!_dbus_get_shm_name(&shm_name,scope)) { _dbus_string_free( &shm_name ); _dbus_global_unlock( lock ); return FALSE; } // create shm len = strlen (address) + 1; hDBusSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, len >> 32, len & 0xffffffffu, _dbus_string_get_const_data(&shm_name) ); _dbus_assert( hDBusSharedMem ); shared_addr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 ); _dbus_assert (shared_addr); strcpy( shared_addr, address); // cleanup UnmapViewOfFile( shared_addr ); _dbus_global_unlock( lock ); _dbus_verbose( "published session bus address at %s\n",_dbus_string_get_const_data (&shm_name) ); _dbus_string_free( &shm_name ); return TRUE; } void _dbus_daemon_unpublish_session_bus_address (void) { HANDLE lock; // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs lock = _dbus_global_lock( cUniqueDBusInitMutex ); CloseHandle( hDBusSharedMem ); hDBusSharedMem = NULL; ReleaseMutex( hDBusDaemonMutex ); CloseHandle( hDBusDaemonMutex ); hDBusDaemonMutex = NULL; _dbus_global_unlock( lock ); } static dbus_bool_t _dbus_get_autolaunch_shm (DBusString *address, DBusString *shm_name) { HANDLE sharedMem; char *shared_addr; int i; // read shm for(i=0;i<20;++i) { // we know that dbus-daemon is available, so we wait until shm is available sharedMem = OpenFileMappingA( FILE_MAP_READ, FALSE, _dbus_string_get_const_data(shm_name)); if( sharedMem == 0 ) Sleep( 100 ); if ( sharedMem != 0) break; } if( sharedMem == 0 ) return FALSE; shared_addr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 ); if( !shared_addr ) return FALSE; _dbus_string_init( address ); _dbus_string_append( address, shared_addr ); // cleanup UnmapViewOfFile( shared_addr ); CloseHandle( sharedMem ); return TRUE; } static dbus_bool_t _dbus_daemon_already_runs (DBusString *address, DBusString *shm_name, const char *scope) { HANDLE lock; HANDLE daemon; DBusString mutex_name; dbus_bool_t bRet = TRUE; if (!_dbus_get_mutex_name(&mutex_name,scope)) { _dbus_string_free( &mutex_name ); return FALSE; } // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs lock = _dbus_global_lock( cUniqueDBusInitMutex ); // do checks daemon = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) ); if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT) { ReleaseMutex (daemon); CloseHandle (daemon); _dbus_global_unlock( lock ); _dbus_string_free( &mutex_name ); return FALSE; } // read shm bRet = _dbus_get_autolaunch_shm( address, shm_name ); // cleanup CloseHandle ( daemon ); _dbus_global_unlock( lock ); _dbus_string_free( &mutex_name ); return bRet; } dbus_bool_t _dbus_get_autolaunch_address (const char *scope, DBusString *address, DBusError *error) { HANDLE mutex; STARTUPINFOA si; PROCESS_INFORMATION pi; dbus_bool_t retval = FALSE; LPSTR lpFile; char dbus_exe_path[MAX_PATH]; char dbus_args[MAX_PATH * 2]; const char * daemon_name = DBUS_DAEMON_NAME ".exe"; DBusString shm_name; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_get_shm_name(&shm_name,scope)) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not determine shm name"); return FALSE; } mutex = _dbus_global_lock ( cDBusAutolaunchMutex ); if (_dbus_daemon_already_runs(address,&shm_name,scope)) { _dbus_verbose( "found running dbus daemon for scope '%s' at %s\n", scope ? scope : "", _dbus_string_get_const_data (&shm_name) ); retval = TRUE; goto out; } if (!SearchPathA(NULL, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) { // Look in directory containing dbus shared library HMODULE hmod; char dbus_module_path[MAX_PATH]; DWORD rc; _dbus_verbose( "did not found dbus daemon executable on default search path, " "trying path where dbus shared library is located"); hmod = _dbus_win_get_dll_hmodule(); rc = GetModuleFileNameA(hmod, dbus_module_path, sizeof(dbus_module_path)); if (rc <= 0) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not retrieve dbus shared library file name"); retval = FALSE; goto out; } else { char *ext_idx = strrchr(dbus_module_path, '\\'); if (ext_idx) *ext_idx = '\0'; if (!SearchPathA(dbus_module_path, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not find dbus-daemon executable"); retval = FALSE; printf ("please add the path to %s to your PATH environment variable\n", daemon_name); printf ("or start the daemon manually\n\n"); goto out; } _dbus_verbose( "found dbus daemon executable at %s",dbus_module_path); } } // Create process ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); _snprintf(dbus_args, sizeof(dbus_args) - 1, "\"%s\" %s", dbus_exe_path, " --session"); // argv[i] = "--config-file=bus\\session.conf"; // printf("create process \"%s\" %s\n", dbus_exe_path, dbus_args); if(CreateProcessA(dbus_exe_path, dbus_args, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { CloseHandle (pi.hThread); CloseHandle (pi.hProcess); retval = _dbus_get_autolaunch_shm( address, &shm_name ); if (retval == FALSE) dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to get autolaunch address from launched dbus-daemon"); } else { dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to launch dbus-daemon"); retval = FALSE; } out: if (retval) _DBUS_ASSERT_ERROR_IS_CLEAR (error); else _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_global_unlock (mutex); _dbus_string_free (&shm_name); return retval; } /** Makes the file readable by every user in the system. * * @param filename the filename * @param error error location * @returns #TRUE if the file's permissions could be changed. */ dbus_bool_t _dbus_make_file_world_readable(const DBusString *filename, DBusError *error) { // TODO return TRUE; } /** * Atomically increments an integer * * @param atomic pointer to the integer to increment * @returns the value before incrementing * */ dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic) { // +/- 1 is needed here! // no volatile argument with mingw return InterlockedIncrement (&atomic->value) - 1; } /** * Atomically decrement an integer * * @param atomic pointer to the integer to decrement * @returns the value before decrementing * */ dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic) { // +/- 1 is needed here! // no volatile argument with mingw return InterlockedDecrement (&atomic->value) + 1; } /** * Atomically get the value of an integer. It may change at any time * thereafter, so this is mostly only useful for assertions. * * @param atomic pointer to the integer to get * @returns the value at this moment */ dbus_int32_t _dbus_atomic_get (DBusAtomic *atomic) { /* In this situation, GLib issues a MemoryBarrier() and then returns * atomic->value. However, mingw from mingw.org (not to be confused with * mingw-w64 from mingw-w64.sf.net) does not have MemoryBarrier in its * headers, so we have to get a memory barrier some other way. * * InterlockedIncrement is older, and is documented on MSDN to be a full * memory barrier, so let's use that. */ long dummy = 0; InterlockedExchange (&dummy, 1); return atomic->value; } /** * Called when the bus daemon is signaled to reload its configuration; any * caches should be nuked. Of course any caches that need explicit reload * are probably broken, but c'est la vie. * * */ void _dbus_flush_caches (void) { } /** * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently * for Winsock so is abstracted) * * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK */ dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (int e) { return e == WSAEWOULDBLOCK; } /** * return the absolute path of the dbus installation * * @param prefix buffer for installation path * @param len length of buffer * @returns #FALSE on failure */ dbus_bool_t _dbus_get_install_root(char *prefix, int len) { //To find the prefix, we cut the filename and also \bin\ if present DWORD pathLength; char *lastSlash; SetLastError( 0 ); pathLength = GetModuleFileNameA(_dbus_win_get_dll_hmodule(), prefix, len); if ( pathLength == 0 || GetLastError() != 0 ) { *prefix = '\0'; return FALSE; } lastSlash = _mbsrchr(prefix, '\\'); if (lastSlash == NULL) { *prefix = '\0'; return FALSE; } //cut off binary name lastSlash[1] = 0; //cut possible "\\bin" //this fails if we are in a double-byte system codepage and the //folder's name happens to end with the *bytes* //"\\bin"... (I.e. the second byte of some Han character and then //the Latin "bin", but that is not likely I think... if (lastSlash - prefix >= 4 && strnicmp(lastSlash - 4, "\\bin", 4) == 0) lastSlash[-3] = 0; else if (lastSlash - prefix >= 10 && strnicmp(lastSlash - 10, "\\bin\\debug", 10) == 0) lastSlash[-9] = 0; else if (lastSlash - prefix >= 12 && strnicmp(lastSlash - 12, "\\bin\\release", 12) == 0) lastSlash[-11] = 0; return TRUE; } /* See comment in dbus-sysdeps-unix.c */ dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported, DBusString *address, DBusError *error) { /* Probably fill this in with something based on COM? */ *supported = FALSE; return TRUE; } /** * Appends the directory in which a keyring for the given credentials * should be stored. The credentials should have either a Windows or * UNIX user in them. The directory should be an absolute path. * * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably * be something else, since the dotfile convention is not normal on Windows. * * @param directory string to append directory to * @param credentials credentials the directory should be for * * @returns #FALSE on no memory */ dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString *directory, DBusCredentials *credentials) { DBusString homedir; DBusString dotdir; const char *homepath; const char *homedrive; _dbus_assert (credentials != NULL); _dbus_assert (!_dbus_credentials_are_anonymous (credentials)); if (!_dbus_string_init (&homedir)) return FALSE; homedrive = _dbus_getenv("HOMEDRIVE"); if (homedrive != NULL && *homedrive != '\0') { _dbus_string_append(&homedir,homedrive); } homepath = _dbus_getenv("HOMEPATH"); if (homepath != NULL && *homepath != '\0') { _dbus_string_append(&homedir,homepath); } #ifdef DBUS_ENABLE_EMBEDDED_TESTS { const char *override; override = _dbus_getenv ("DBUS_TEST_HOMEDIR"); if (override != NULL && *override != '\0') { _dbus_string_set_length (&homedir, 0); if (!_dbus_string_append (&homedir, override)) goto failed; _dbus_verbose ("Using fake homedir for testing: %s\n", _dbus_string_get_const_data (&homedir)); } else { /* Not strictly thread-safe, but if we fail at thread-safety here, * the worst that will happen is some extra warnings. */ static dbus_bool_t already_warned = FALSE; if (!already_warned) { _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n"); already_warned = TRUE; } } } #endif #ifdef DBUS_WINCE /* It's not possible to create a .something directory in Windows CE using the file explorer. */ #define KEYRING_DIR "dbus-keyrings" #else #define KEYRING_DIR ".dbus-keyrings" #endif _dbus_string_init_const (&dotdir, KEYRING_DIR); if (!_dbus_concat_dir_and_file (&homedir, &dotdir)) goto failed; if (!_dbus_string_copy (&homedir, 0, directory, _dbus_string_get_length (directory))) { goto failed; } _dbus_string_free (&homedir); return TRUE; failed: _dbus_string_free (&homedir); return FALSE; } /** Checks if a file exists * * @param file full path to the file * @returns #TRUE if file exists */ dbus_bool_t _dbus_file_exists (const char *file) { DWORD attributes = GetFileAttributesA (file); if (attributes != INVALID_FILE_ATTRIBUTES && GetLastError() != ERROR_PATH_NOT_FOUND) return TRUE; else return FALSE; } /** * A wrapper around strerror() because some platforms * may be lame and not have strerror(). * * @param error_number errno. * @returns error description. */ const char* _dbus_strerror (int error_number) { #ifdef DBUS_WINCE // TODO return "unknown"; #else const char *msg; switch (error_number) { case WSAEINTR: return "Interrupted function call"; case WSAEACCES: return "Permission denied"; case WSAEFAULT: return "Bad address"; case WSAEINVAL: return "Invalid argument"; case WSAEMFILE: return "Too many open files"; case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; case WSAEINPROGRESS: return "Operation now in progress"; case WSAEALREADY: return "Operation already in progress"; case WSAENOTSOCK: return "Socket operation on nonsocket"; case WSAEDESTADDRREQ: return "Destination address required"; case WSAEMSGSIZE: return "Message too long"; case WSAEPROTOTYPE: return "Protocol wrong type for socket"; case WSAENOPROTOOPT: return "Bad protocol option"; case WSAEPROTONOSUPPORT: return "Protocol not supported"; case WSAESOCKTNOSUPPORT: return "Socket type not supported"; case WSAEOPNOTSUPP: return "Operation not supported"; case WSAEPFNOSUPPORT: return "Protocol family not supported"; case WSAEAFNOSUPPORT: return "Address family not supported by protocol family"; case WSAEADDRINUSE: return "Address already in use"; case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; case WSAENETDOWN: return "Network is down"; case WSAENETUNREACH: return "Network is unreachable"; case WSAENETRESET: return "Network dropped connection on reset"; case WSAECONNABORTED: return "Software caused connection abort"; case WSAECONNRESET: return "Connection reset by peer"; case WSAENOBUFS: return "No buffer space available"; case WSAEISCONN: return "Socket is already connected"; case WSAENOTCONN: return "Socket is not connected"; case WSAESHUTDOWN: return "Cannot send after socket shutdown"; case WSAETIMEDOUT: return "Connection timed out"; case WSAECONNREFUSED: return "Connection refused"; case WSAEHOSTDOWN: return "Host is down"; case WSAEHOSTUNREACH: return "No route to host"; case WSAEPROCLIM: return "Too many processes"; case WSAEDISCON: return "Graceful shutdown in progress"; case WSATYPE_NOT_FOUND: return "Class type not found"; case WSAHOST_NOT_FOUND: return "Host not found"; case WSATRY_AGAIN: return "Nonauthoritative host not found"; case WSANO_RECOVERY: return "This is a nonrecoverable error"; case WSANO_DATA: return "Valid name, no data record of requested type"; case WSA_INVALID_HANDLE: return "Specified event object handle is invalid"; case WSA_INVALID_PARAMETER: return "One or more parameters are invalid"; case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state"; case WSA_IO_PENDING: return "Overlapped operations will complete later"; case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available"; case WSA_OPERATION_ABORTED: return "Overlapped operation aborted"; #ifdef WSAINVALIDPROCTABLE case WSAINVALIDPROCTABLE: return "Invalid procedure table from service provider"; #endif #ifdef WSAINVALIDPROVIDER case WSAINVALIDPROVIDER: return "Invalid service provider version number"; #endif #ifdef WSAPROVIDERFAILEDINIT case WSAPROVIDERFAILEDINIT: return "Unable to initialize a service provider"; #endif case WSASYSCALLFAILURE: return "System call failure"; } msg = strerror (error_number); if (msg == NULL) msg = "unknown"; return msg; #endif //DBUS_WINCE } /** * Assigns an error name and message corresponding to a Win32 error * code to a DBusError. Does nothing if error is #NULL. * * @param error the error. * @param code the Win32 error code */ void _dbus_win_set_error_from_win_error (DBusError *error, int code) { char *msg; /* As we want the English message, use the A API */ FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR) &msg, 0, NULL); if (msg) { dbus_set_error (error, "win32.error", "%s", msg); LocalFree (msg); } else dbus_set_error (error, "win32.error", "Unknown error code %d or FormatMessage failed", code); } void _dbus_win_warn_win_error (const char *message, unsigned long code) { DBusError error; dbus_error_init (&error); _dbus_win_set_error_from_win_error (&error, code); _dbus_warn ("%s: %s\n", message, error.message); dbus_error_free (&error); } /** * Removes a directory; Directory must be empty * * @param filename directory filename * @param error initialized error object * @returns #TRUE on success */ dbus_bool_t _dbus_delete_directory (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (RemoveDirectoryA (filename_c) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to remove directory %s: %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } return TRUE; } /** * Checks whether the filename is an absolute path * * @param filename the filename * @returns #TRUE if an absolute path */ dbus_bool_t _dbus_path_is_absolute (const DBusString *filename) { if (_dbus_string_get_length (filename) > 0) return _dbus_string_get_byte (filename, 1) == ':' || _dbus_string_get_byte (filename, 0) == '\\' || _dbus_string_get_byte (filename, 0) == '/'; else return FALSE; } dbus_bool_t _dbus_check_setuid (void) { return FALSE; } int _dbus_save_socket_errno (void) { return errno; } void _dbus_restore_socket_errno (int saved_errno) { _dbus_win_set_errno (saved_errno); } /** @} end of sysdeps-win */ /* tests in dbus-sysdeps-util.c */ dbus-1.10.6/dbus/dbus-sockets-win.h0000644000175000017500000000272712602773110017054 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sockets.h Wrappers around socket features (internal to D-BUS implementation) * * Copyright (C) 2005 Novell, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SOCKETS_H #define DBUS_SOCKETS_H #if defined(DBUS_WIN) || defined(DBUS_WINCE) #ifndef STRICT #define STRICT #include #undef STRICT #endif #include #undef interface #if HAVE_ERRNO_H #include #endif #define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) == SOCKET_ERROR) #define DBUS_SOCKET_SET_ERRNO() (_dbus_win_set_errno (WSAGetLastError())) #else #error "dbus-sockets-win.h should not be included on non-Windows" #endif /* !Win32 */ #endif /* DBUS_SOCKETS_H */ dbus-1.10.6/dbus/dbus-pipe-win.c0000644000175000017500000000506712602773110016331 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pipe-win.c windows related pipe implementation * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-internals.h" #include "dbus-pipe.h" #include #include /** * write data to a pipe. * * @param pipe the pipe instance * @param buffer the buffer to write data from * @param start the first byte in the buffer to write * @param len the number of bytes to try to write * @param error error return * @returns the number of bytes written or -1 on error */ int _dbus_pipe_write (DBusPipe *pipe, const DBusString *buffer, int start, int len, DBusError *error) { const char *buffer_c = _dbus_string_get_const_data (buffer); int written; written = _write (pipe->fd, buffer_c + start, len); if (written >= 0) return written; dbus_set_error (error, _dbus_error_from_system_errno (), "Writing to pipe: %s", _dbus_strerror_from_errno ()); return -1; } /** * close a pipe. * * @param pipe the pipe instance * @param error return location for an error * @returns #FALSE if error is set */ int _dbus_pipe_close (DBusPipe *pipe, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_close (pipe->fd) != 0) { dbus_set_error (error, _dbus_error_from_system_errno (), "Could not close pipe fd %d: %s", pipe->fd, _dbus_strerror_from_errno ()); return -1; } else { _dbus_pipe_invalidate (pipe); return 0; } } dbus-1.10.6/dbus/dbus-file-win.c0000644000175000017500000002657412602773110016321 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-file-win.c windows related file implementation (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-internals.h" #include "dbus-sysdeps-win.h" #include "dbus-pipe.h" #include /** * Thin wrapper around the read() system call that appends * the data it reads to the DBusString buffer. It appends * up to the given count. * * @param hnd the HANDLE to read from * @param buffer the buffer to append data to * @param count the amount of data to read * @param error place to set an error * @returns the number of bytes read or -1 */ static int _dbus_file_read (HANDLE hnd, DBusString *buffer, int count, DBusError *error) { BOOL result; DWORD bytes_read; int start; char *data; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (count >= 0); start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return -1; } data = _dbus_string_get_data_len (buffer, start, count); result = ReadFile (hnd, data, count, &bytes_read, NULL); if (result == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to read from 0x%x: %s", hnd, emsg); _dbus_win_free_error_string (emsg); return -1; } if (bytes_read) { /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); #if 0 if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif } return bytes_read; } /** * Appends the contents of the given file to the string, * returning error code. At the moment, won't open a file * more than a megabyte in size. * * @param str the string to append to * @param filename filename to load * @param error place to set an error * @returns #FALSE if error was set */ dbus_bool_t _dbus_file_get_contents (DBusString *str, const DBusString *filename, DBusError *error) { HANDLE hnd; DWORD fsize; DWORD fsize_hi; int orig_len; unsigned int total; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); hnd = CreateFileA (filename_c, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hnd == INVALID_HANDLE_VALUE) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to open \"%s\": %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } _dbus_verbose ("file %s hnd %p opened\n", filename_c, hnd); fsize = GetFileSize (hnd, &fsize_hi); if (fsize == 0xFFFFFFFF && GetLastError() != NO_ERROR) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to get file size for \"%s\": %s", filename_c, emsg); _dbus_win_free_error_string (emsg); _dbus_verbose ("GetFileSize() failed: %s", emsg); CloseHandle (hnd); return FALSE; } if (fsize_hi != 0 || fsize > _DBUS_ONE_MEGABYTE) { dbus_set_error (error, DBUS_ERROR_FAILED, "File size %lu/%lu of \"%s\" is too large.", (unsigned long) fsize_hi, (unsigned long) fsize, filename_c); CloseHandle (hnd); return FALSE; } total = 0; orig_len = _dbus_string_get_length (str); if (fsize > 0) { int bytes_read; while (total < fsize) { bytes_read = _dbus_file_read (hnd, str, fsize - total, error); if (bytes_read <= 0) { if (bytes_read == 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Premature EOF reading \"%s\"", filename_c); } else _DBUS_ASSERT_ERROR_IS_SET (error); CloseHandle (hnd); _dbus_string_set_length (str, orig_len); return FALSE; } else total += bytes_read; } CloseHandle (hnd); return TRUE; } else { CloseHandle (hnd); return TRUE; } } /** * Writes a string out to a file. If the file exists, * it will be atomically overwritten by the new data. * * @param str the string to write out * @param filename the file to save string to * @param world_readable if true, ensure file is world readable * @param error error to be filled in on failure * @returns #FALSE on failure */ dbus_bool_t _dbus_string_save_to_file (const DBusString *str, const DBusString *filename, dbus_bool_t world_readable, DBusError *error) { HANDLE hnd; int bytes_to_write; const char *filename_c; DBusString tmp_filename; const char *tmp_filename_c; int total; const char *str_c; dbus_bool_t need_unlink; dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); hnd = INVALID_HANDLE_VALUE; retval = FALSE; need_unlink = FALSE; if (!_dbus_string_init (&tmp_filename)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&tmp_filename); return FALSE; } if (!_dbus_string_append (&tmp_filename, ".")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&tmp_filename); return FALSE; } #define N_TMP_FILENAME_RANDOM_BYTES 8 if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES, error)) { _dbus_string_free (&tmp_filename); return FALSE; } filename_c = _dbus_string_get_const_data (filename); tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); /* TODO - support world-readable in an atomic fashion */ hnd = CreateFileA (tmp_filename_c, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hnd == INVALID_HANDLE_VALUE) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not create \"%s\": %s", filename_c, emsg); _dbus_win_free_error_string (emsg); goto out; } if (world_readable) { if (! _dbus_make_file_world_readable (&tmp_filename, error)) goto out; } _dbus_verbose ("tmp file %s hnd %p opened\n", tmp_filename_c, hnd); need_unlink = TRUE; total = 0; bytes_to_write = _dbus_string_get_length (str); str_c = _dbus_string_get_const_data (str); while (total < bytes_to_write) { DWORD bytes_written; BOOL res; res = WriteFile (hnd, str_c + total, bytes_to_write - total, &bytes_written, NULL); if (res == 0 || bytes_written <= 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not write to %s: %s", tmp_filename_c, emsg); _dbus_win_free_error_string (emsg); goto out; } total += bytes_written; } if (CloseHandle (hnd) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not close file %s: %s", tmp_filename_c, emsg); _dbus_win_free_error_string (emsg); goto out; } hnd = INVALID_HANDLE_VALUE; /* Unlike rename(), MoveFileEx() can replace existing files */ if (!MoveFileExA (tmp_filename_c, filename_c, MOVEFILE_REPLACE_EXISTING)) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not rename %s to %s: %s", tmp_filename_c, filename_c, emsg); _dbus_win_free_error_string (emsg); goto out; } need_unlink = FALSE; retval = TRUE; out: /* close first, then unlink */ if (hnd != INVALID_HANDLE_VALUE) CloseHandle (hnd); if (need_unlink && DeleteFileA (tmp_filename_c) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); _dbus_verbose ("Failed to unlink temp file %s: %s", tmp_filename_c, emsg); _dbus_win_free_error_string (emsg); } _dbus_string_free (&tmp_filename); if (!retval) _DBUS_ASSERT_ERROR_IS_SET (error); return retval; } /** Creates the given file, failing if the file already exists. * * @param filename the filename * @param error error location * @returns #TRUE if we created the file and it didn't exist */ dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename, DBusError *error) { HANDLE hnd; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); hnd = CreateFileA (filename_c, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hnd == INVALID_HANDLE_VALUE) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not create file %s: %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } _dbus_verbose ("exclusive file %s hnd %p opened\n", filename_c, hnd); if (CloseHandle (hnd) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not close file %s: %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } return TRUE; } dbus-1.10.6/dbus/dbus-sysdeps-wince-glue.c0000644000175000017500000006163112602773110020327 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-wince-glue.c Wrappers for Windows CE around system/libc features (internal to D-BUS implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2005 Novell, Inc. * Copyright (C) 2006 Ralf Habacker * Copyright (C) 2006 Peter Kümmel * Copyright (C) 2006 Christian Ehrlicher * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-win.h" #include /* Including shlobj.h creates trouble on some compilers. Just chicken out here by defining just what we need. */ #ifndef CSIDL_PERSONAL #define CSIDL_PERSONAL 5 #endif /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ static char * stpcpy (char *dest, const char *src) { char *d = dest; const char *s = src; do *d++ = *s; while (*s++ != '\0'); return d - 1; } /* This is special cased, because we must avoid using many dbus functions (such as memory allocations): Those functions may in turn cause verbose output and check the flag! */ static char * get_verbose_setting() { const wchar_t dir[] = L"Software\\freedesktop\\DBus"; const wchar_t name[] = L"Verbose"; HKEY root_key; HKEY key_handle; DWORD nbytes; DWORD n1; DWORD type; wchar_t *result_w = NULL; char *result; int len; root_key = HKEY_LOCAL_MACHINE; if (RegOpenKeyExW (root_key, dir, 0, KEY_READ, &key_handle)) return NULL; nbytes = 1; if (RegQueryValueExW (key_handle, name, 0, NULL, NULL, &nbytes)) { RegCloseKey (key_handle); return NULL; } /* Round up to multiple of wchar_t, convert to number of wchar_t's, and add 1. */ n1 = ((nbytes + sizeof(wchar_t) - 1) / sizeof (wchar_t)) + 1; result_w = malloc (n1 * sizeof (wchar_t)); if (!result_w) { RegCloseKey (key_handle); return NULL; } if (RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) result_w, &nbytes)) { RegCloseKey (key_handle); free (result_w); return NULL; } RegCloseKey (key_handle); result_w[n1 - 1] = 0; /* Make sure it is really a string. */ /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they are not needed in this module. */ if (type != REG_SZ) { free (result_w); return NULL; } len = WideCharToMultiByte (CP_UTF8, 0, result_w, -1, NULL, 0, NULL, NULL); if (len < 0) { free (result_w); return NULL; } result = malloc (len + 1); if (!result) { free (result_w); return NULL; } len = WideCharToMultiByte (CP_UTF8, 0, result_w, -1, result, len, NULL, NULL); free (result_w); if (len < 0) { free (result); return NULL; } return result; } /* Return a string from the W32 Registry or NULL in case of error. Caller must release the return value. A NULL for root is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */ static char * read_w32_registry_string (const char *root, const char *dir, const char *name) { HKEY root_key, key_handle; DWORD n1, nbytes, type; char *result = NULL; if ( !root ) root_key = HKEY_CURRENT_USER; else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if ( !strcmp( root, "HKEY_CURRENT_USER" ) ) root_key = HKEY_CURRENT_USER; else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) root_key = HKEY_LOCAL_MACHINE; else if ( !strcmp( root, "HKEY_USERS" ) ) root_key = HKEY_USERS; else return NULL; if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle)) { if (root) return NULL; /* no need for a RegClose, so return direct */ /* It seems to be common practise to fall back to HKLM. */ if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) return NULL; /* still no need for a RegClose, so return direct */ } nbytes = 1; if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes)) { if (root) goto out; /* Try to fallback to HKLM also for a missing value. */ RegCloseKey (key_handle); if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) return NULL; /* Nope. */ if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes)) goto out; } n1 = nbytes + 1; result = malloc (n1); if (!result) goto out; if (RegQueryValueExA (key_handle, name, 0, &type, result, &n1)) { free(result); result = NULL; goto out; } result[nbytes] = 0; /* Make sure it is really a string. */ out: RegCloseKey (key_handle); return result; } static char * find_inst_dir () { return read_w32_registry_string ("HKEY_LOCAL_MACHINE", "Software\\freedesktop\\DBus", "Install Directory"); } static char * find_env_in_registry (const char *name) { return read_w32_registry_string ("HKEY_LOCAL_MACHINE", "Software\\freedesktop\\DBus", name); } static char * find_program_in_inst_dir (const char *name) { char *result = NULL; char *tmp; tmp = find_inst_dir (); if (!tmp) return NULL; result = malloc (strlen (tmp) + 5 + strlen (name) + 1); if (!result) { free (tmp); return NULL; } strcpy (stpcpy (stpcpy (result, tmp), "\\bin\\"), name); free (tmp); return result; } static char * find_inst_subdir (const char *name) { char *result = NULL; char *tmp; tmp = find_inst_dir (); if (!tmp) return NULL; result = malloc (strlen (tmp) + 1 + strlen (name) + 1); if (!result) { free (tmp); return NULL; } strcpy (stpcpy (stpcpy (result, tmp), "\\"), name); free (tmp); return result; } static char * find_my_documents_folder () { /* One for safety, just in case. */ char dir[MAX_PATH + 1]; char *result; dir[0] = '\0'; /* May return false even if successful. */ SHGetSpecialFolderPathA (0, dir, CSIDL_PERSONAL, 0); if (dir[0] == '\0') return NULL; result = malloc (strlen (dir) + 1); if (!result) return NULL; strcpy (result, dir); return result; } #define MAX_ENV 30 char *environ[MAX_ENV + 1]; char * getenv (const char *name) { static char *past_result; char **envp; int idx; if (past_result) { free (past_result); past_result = NULL; } if (! strcmp (name, "DBUS_VERBOSE")) return past_result = get_verbose_setting (); else if (! strcmp (name, "HOMEPATH")) return past_result = find_my_documents_folder (); else if (! strcmp (name, "DBUS_DATADIR")) return past_result = find_inst_subdir ("share"); for (envp = environ; *envp != 0; envp++) { const char *varp = name; char *ep = *envp; int same_name = 0; while (*varp == *ep && *varp != '\0') { ++ep; ++varp; }; if (*varp == '\0' && *ep == '=') return ep + 1; } return NULL; } int putenv (char *str) { char **envp; int idx; for (envp = environ; *envp != 0; envp++) { char *varp = str; char *ep = *envp; int same_name = 0; while (*varp == *ep && *varp != '\0') { if (*varp == '=') same_name = 1; ++ep; ++varp; }; if (*varp == *ep && *varp == '\0') return 0; if (same_name) { *envp = str; return 0; } } idx = envp - environ; if (idx > MAX_ENV) { _dbus_win_set_errno (ENOMEM); return -1; } environ[idx] = str; return 0; } clock_t clock (void) { return GetTickCount (); } void abort (void) { /* This is what windows does. */ exit (3); } void GetSystemTimeAsFileTime (LPFILETIME ftp) { SYSTEMTIME st; GetSystemTime (&st); SystemTimeToFileTime (&st, ftp); } unsigned char* _mbsrchr (const unsigned char* str, unsigned int ch) { /* FIXME. This is not multi-byte safe. */ return strrchr (str, ch); } HANDLE OpenFileMappingA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { DWORD flProtect = 0; HANDLE hMapping; if (dwDesiredAccess & FILE_MAP_READ) flProtect |= PAGE_READONLY; if (dwDesiredAccess & FILE_MAP_WRITE) flProtect |= PAGE_READWRITE; SetLastError (0); hMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, flProtect, 0, 0, lpName); if (hMapping != INVALID_HANDLE_VALUE) { /* Just in case Windows CE changes its behaviour, we check for the right error value here. */ if (GetLastError () != ERROR_ALREADY_EXISTS) { CloseHandle(hMapping); hMapping = INVALID_HANDLE_VALUE; } } return hMapping; } BOOL MoveFileExA (LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags) { _dbus_assert (dwFlags == MOVEFILE_REPLACE_EXISTING); if (_dbus_file_exists (lpNewFileName)) { BOOL result = DeleteFileA (lpNewFileName); if (result == 0) return FALSE; } return MoveFileA (lpExistingFileName, lpNewFileName); } BOOL SetHandleInformation (HANDLE hObject, DWORD dwMask, DWORD dwFlags) { _dbus_assert (dwMask == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)); _dbus_assert (dwFlags == 0); /* Not supported on Windows CE, and actually the default. So just return overwhelming success. */ return 1; } DWORD SearchPathA (LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart) { char *filename; char *filepart; int filename_len; _dbus_assert (lpPath == NULL); _dbus_assert (lpExtension == NULL); filename = find_program_in_inst_dir (lpFileName); if (!filename) { SetLastError (ERROR_FILE_NOT_FOUND); return 0; } filename_len = strlen (filename) + 1; if (filename_len > nBufferLength) { free (filename); return filename_len; } strcpy (lpBuffer, filename); free (filename); filepart = _mbsrchr (lpBuffer, '\\'); if (!filepart) filepart = lpBuffer; *lpFilePart = filepart; return filename_len - 1; } /** Gets our SID * @param sid points to sid buffer, need to be freed with LocalFree() * @returns process sid */ dbus_bool_t _dbus_getsid(char **sid) { /* There is nothing like this on Windows CE, so we fake it. */ static const char asid[] = "S-1-5-21-515967899-920026266-1708537768-1000"; char *buf = LocalAlloc (LMEM_FIXED, sizeof (asid)); if (!buf) { _dbus_win_warn_win_error ("LocalAlloc failed", GetLastError ()); return FALSE; } memcpy (buf, asid, sizeof (asid)); *sid = buf; return TRUE; } BOOL LookupAccountNameW (LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, PDWORD cbSid, LPWSTR ReferencedDomainName, PDWORD cchReferencedDomainName, PSID_NAME_USE peUse) { /* Currently not needed. */ return FALSE; } BOOL IsValidSid (PSID psid) { /* Currently not needed. */ return FALSE; } HANDLE CreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { wchar_t *filename; HANDLE result; int err; filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL); if (!filename) return INVALID_HANDLE_VALUE; result = CreateFileW (filename, dwDesiredAccess, dwSharedMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); err = GetLastError (); dbus_free (filename); SetLastError (err); return result; } BOOL DeleteFileA (LPCSTR lpFileName) { wchar_t *filename; BOOL result; int err; filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL); if (!filename) return FALSE; result = DeleteFileW (filename); err = GetLastError (); dbus_free (filename); SetLastError (err); return result; } BOOL MoveFileA (LPCSTR lpExistingFileName, LPCSTR lpNewFileName) { wchar_t *existing_filename; wchar_t *new_filename; BOOL result; int err; existing_filename = _dbus_win_utf8_to_utf16 (lpExistingFileName, NULL); if (! existing_filename) return FALSE; new_filename = _dbus_win_utf8_to_utf16 (lpNewFileName, NULL); if (! new_filename) { dbus_free (existing_filename); return FALSE; } result = MoveFileW (existing_filename, new_filename); err = GetLastError (); dbus_free (existing_filename); dbus_free (new_filename); SetLastError (err); return result; } DWORD GetFileAttributesA(LPCSTR lpFileName) { wchar_t *filename; DWORD result; int err; filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL); if (!filename) return INVALID_FILE_ATTRIBUTES; result = GetFileAttributesW (filename); err = GetLastError (); dbus_free (filename); SetLastError (err); return result; } BOOL GetFileAttributesExA (LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, PVOID lpFileInformation) { wchar_t *filename; DWORD result; int err; filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL); if (!filename) return INVALID_FILE_ATTRIBUTES; result = GetFileAttributesExW (filename, fInfoLevelId, lpFileInformation); err = GetLastError (); dbus_free (filename); SetLastError (err); return result; } HANDLE CreateFileMappingA (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) { wchar_t *name; HANDLE result; int err; if (lpName) { name = _dbus_win_utf8_to_utf16 (lpName, NULL); if (!name) return INVALID_HANDLE_VALUE; } else name = NULL; result = CreateFileMappingW (hFile, lpAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, name); err = GetLastError (); dbus_free (name); SetLastError (err); return result; } BOOL CreateDirectoryA (LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { wchar_t *pathname; BOOL result; int err; pathname = _dbus_win_utf8_to_utf16 (lpPathName, NULL); if (!pathname) return FALSE; result = CreateDirectoryW (pathname, lpSecurityAttributes); err = GetLastError (); dbus_free (pathname); SetLastError (err); return result; } BOOL RemoveDirectoryA (LPCSTR lpPathName) { wchar_t *pathname; BOOL result; int err; pathname = _dbus_win_utf8_to_utf16 (lpPathName, NULL); if (!pathname) return FALSE; result = RemoveDirectoryW (pathname); err = GetLastError (); dbus_free (pathname); SetLastError (err); return result; } static BOOL convert_find_data (LPWIN32_FIND_DATAW fdw, LPWIN32_FIND_DATAA fda) { char *filename; int len; fda->dwFileAttributes = fdw->dwFileAttributes; fda->ftCreationTime = fdw->ftCreationTime; fda->ftLastAccessTime = fdw->ftLastAccessTime; fda->ftLastWriteTime = fdw->ftLastWriteTime; fda->nFileSizeHigh = fdw->nFileSizeHigh; fda->nFileSizeLow = fdw->nFileSizeLow; filename = _dbus_win_utf16_to_utf8 (fdw->cFileName, NULL); if (!filename) return FALSE; len = sizeof (fda->cFileName); strncpy (fda->cFileName, filename, len); fda->cFileName[len - 1] = '\0'; return TRUE; } HANDLE FindFirstFileA (LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) { wchar_t *pathname; WIN32_FIND_DATAW find_file_data; HANDLE result; int err; pathname = _dbus_win_utf8_to_utf16 (lpFileName, NULL); if (!pathname) return INVALID_HANDLE_VALUE; result = FindFirstFileW (pathname, &find_file_data); if (result != INVALID_HANDLE_VALUE) { BOOL res = convert_find_data (&find_file_data, lpFindFileData); if (! res) { err = GetLastError (); FindClose (result); SetLastError (err); result = INVALID_HANDLE_VALUE; } } err = GetLastError (); dbus_free (pathname); SetLastError (err); return result; } BOOL FindNextFileA (HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) { WIN32_FIND_DATAW find_file_data; BOOL result; int err; result = FindNextFileW (hFindFile, &find_file_data); if (result) result = convert_find_data (&find_file_data, lpFindFileData); return result; } HANDLE CreateMutexA (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName) { wchar_t *name; HANDLE result; int err; if (lpName) { name = _dbus_win_utf8_to_utf16 (lpName, NULL); if (!name) return INVALID_HANDLE_VALUE; } else name = NULL; result = CreateMutexW (lpMutexAttributes, bInitialOwner, name); err = GetLastError (); dbus_free (name); SetLastError (err); return result; } BOOL CreateProcessA (LPCSTR pszImageName, LPSTR pszCmdLine, LPSECURITY_ATTRIBUTES psaProcess, LPSECURITY_ATTRIBUTES psaThread, BOOL fInheritHandles, DWORD fdwCreate, PVOID pvEnvironment, LPCSTR pszCurDir, LPSTARTUPINFOA psiStartInfo, LPPROCESS_INFORMATION pProcInfo) { wchar_t *image_name = NULL; wchar_t *cmd_line = NULL; BOOL result; int err; _dbus_assert (psaProcess == NULL); _dbus_assert (psaThread == NULL); _dbus_assert (fInheritHandles == FALSE); _dbus_assert (pvEnvironment == NULL); _dbus_assert (pszCurDir == NULL); /* psiStartInfo is generally not NULL. */ if (pszImageName) { image_name = _dbus_win_utf8_to_utf16 (pszImageName, NULL); if (!image_name) return 0; } if (pszCmdLine) { cmd_line = _dbus_win_utf8_to_utf16 (pszCmdLine, NULL); if (!cmd_line) { if (image_name) dbus_free (image_name); return 0; } } result = CreateProcessW (image_name, cmd_line, NULL, NULL, FALSE, fdwCreate, NULL, NULL, NULL, pProcInfo); err = GetLastError (); dbus_free (image_name); dbus_free (cmd_line); SetLastError (err); return result; } LONG RegOpenKeyExA (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { wchar_t *subkey; LONG result; int err; if (lpSubKey) { subkey = _dbus_win_utf8_to_utf16 (lpSubKey, NULL); if (!subkey) return 0; } else subkey = NULL; result = RegOpenKeyEx (hKey, subkey, ulOptions, samDesired, phkResult); err = GetLastError (); dbus_free (subkey); SetLastError (err); return result; } LONG RegQueryValueExA (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) { wchar_t *name; LONG err; BYTE *data; DWORD data_len; DWORD type; if (lpValueName) { name = _dbus_win_utf8_to_utf16 (lpValueName, NULL); if (!name) return GetLastError (); } else name = NULL; data_len = 0; err = RegQueryValueExW (hKey, name, lpReserved, lpType, NULL, &data_len); if (err || !lpcbData) { dbus_free (name); return err; } data = malloc (data_len + sizeof (wchar_t)); if (!data) { dbus_free (name); return ERROR_NOT_ENOUGH_MEMORY; } err = RegQueryValueExW (hKey, name, lpReserved, &type, data, &data_len); if (lpType) *lpType = type; dbus_free (name); /* If err is ERROR_MORE_DATA, there probably was a race condition. We can punt this to the caller just as well. */ if (err) { free (data); return err; } /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they are not needed in this module. */ if (type == REG_SZ) { char *data_c; int data_c_len; /* This is valid since we allocated one more above. */ data[data_len] = '\0'; data[data_len + 1] = '\0'; /* The cast is valid because malloc guarantees alignment of basic types. */ data_c = _dbus_win_utf16_to_utf8 ((wchar_t*) data, NULL); if (!data_c) { free (data); return GetLastError(); } data_c_len = strlen (data_c) + 1; _dbus_assert (data_c_len <= data_len + sizeof (wchar_t)); memcpy (data, data_c, data_c_len); data_len = data_c_len; dbus_free (data_c); } /* DATA and DATA_LEN now contain the result. */ if (lpData) { if (data_len > *lpcbData) err = ERROR_MORE_DATA; else memcpy (lpData, data, data_len); } free (data); *lpcbData = data_len; return err; } DWORD FormatMessageA (DWORD dwFlags, PCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list* Arguments) { LPWSTR buffer_w = NULL; LPSTR buffer_c; DWORD len; char *buffer_new; DWORD buffer_new_len; BOOL buffer_w_free; len = FormatMessageW (dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpSource, dwMessageId, dwLanguageId, (LPWSTR) &buffer_w, 0, Arguments); if (len == 0) return 0; buffer_c = _dbus_win_utf16_to_utf8 (buffer_w, NULL); if (! buffer_c) { LocalFree (buffer_w); return 0; } if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { /* We need to return a buffer that's freeable with LocalFree. */ buffer_new = (char *) buffer_w; buffer_new_len = sizeof (wchar_t) * (len + 1); buffer_w_free = FALSE; /* Avoid alignment issue by using memcpy. */ memcpy (lpBuffer, &buffer_new, sizeof (buffer_new)); } else { buffer_new = lpBuffer; buffer_new_len = nSize; buffer_w_free = TRUE; } strncpy (buffer_new, buffer_c, buffer_new_len); dbus_free (buffer_c); buffer_new[buffer_new_len - 1] = '\0'; if (buffer_w_free) LocalFree (buffer_w); /* strlen is correct (not _mbstrlen), because we want storage and not string length. */ return strlen (buffer_new); } DWORD GetModuleFileNameA (HINSTANCE hModule, LPSTR lpFilename, DWORD nSize) { wchar_t *filename_w; char *filename_c; DWORD len; if (nSize == 0) { /* Windows XP/2000. */ SetLastError (0); return 0; } filename_w = malloc (sizeof (wchar_t) * nSize); if (! filename_w) return 0; len = GetModuleFileNameW (hModule, filename_w, nSize); if (len == 0) { /* Note: If we fail with ERROR_INSUFFICIENT_BUFFER, this is still (approximately) correct. */ free (filename_w); return 0; } filename_w[nSize - 1] = '\0'; filename_c = _dbus_win_utf16_to_utf8 (filename_w, NULL); free (filename_w); if (! filename_c) return 0; strncpy (lpFilename, filename_c, nSize); dbus_free (filename_c); lpFilename[nSize - 1] = '\0'; /* strlen is correct (not _mbstrlen), because we want storage and not string length. */ return strlen (lpFilename); } DWORD GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer) { wchar_t dummy[1]; DWORD len; len = GetTempPathW (0, dummy); if (len == 0) return 0; _dbus_assert (len <= MAX_PATH); /* Better be safe than sorry. MSDN doesn't say if len is with or without terminating 0. */ len++; { wchar_t *buffer_w; DWORD len_w; char *buffer_c; DWORD len_c; buffer_w = malloc (sizeof (wchar_t) * len); if (! buffer_w) return 0; len_w = GetTempPathW (len, buffer_w); /* Give up if we still can't get at it. */ if (len_w == 0 || len_w >= len) { free (buffer_w); return 0; } /* Better be really safe. */ buffer_w[len_w] = '\0'; buffer_c = _dbus_win_utf16_to_utf8 (buffer_w, NULL); free (buffer_w); if (! buffer_c) return 0; /* strlen is correct (not _mbstrlen), because we want storage and not string length. */ len_c = strlen (buffer_c) + 1; if (len_c > nBufferLength) return len_c; strcpy (lpBuffer, buffer_c); dbus_free (buffer_c); return len_c - 1; } } BOOL SHGetSpecialFolderPathA (HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate) { wchar_t path[MAX_PATH]; char *path_c; BOOL result; path[0] = (wchar_t) 0; result = SHGetSpecialFolderPathW (hwndOwner, path, nFolder, fCreate); /* Note: May return false even if succeeds. */ path[MAX_PATH - 1] = (wchar_t) 0; path_c = _dbus_win_utf16_to_utf8 (path, NULL); if (! path_c) return 0; strncpy (lpszPath, path_c, MAX_PATH); dbus_free (path_c); lpszPath[MAX_PATH - 1] = '\0'; return result; } void OutputDebugStringA (LPCSTR lpOutputString) { wchar_t *str; HANDLE result; int err; str = _dbus_win_utf8_to_utf16 (lpOutputString, NULL); if (!str) return; OutputDebugStringW (str); err = GetLastError (); dbus_free (str); SetLastError (err); } dbus-1.10.6/dbus/dbus-sysdeps-wince-glue.h0000644000175000017500000001735612602773110020341 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-wince-glue.h Emulation of system/libc features for Windows CE (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SYSDEPS_WINCE_GLUE_H #define DBUS_SYSDEPS_WINCE_GLUE_H #include #include /* For getaddrinfo, configure/cmake defined _WIN32_WCE to something >= 0x0401. */ #include #undef interface DBUS_BEGIN_DECLS /* shlobj.h declares these only for _WIN32_IE that we don't want to define. In any case, with mingw32ce we only get a SHGetSpecialFolderPath. */ #define SHGetSpecialFolderPathW SHGetSpecialFolderPath BOOL WINAPI SHGetSpecialFolderPathA(HWND,LPSTR,int,BOOL); BOOL WINAPI SHGetSpecialFolderPathW(HWND,LPWSTR,int,BOOL); #ifndef TLS_OUT_OF_INDEXES #define TLS_OUT_OF_INDEXES 0xffffffff #endif /* Seriously. Windows CE does not have errno. Don't you hate it when that happens? */ #define errno ((int)GetLastError ()) #define ENOENT ERROR_FILE_NOT_FOUND #define EMFILE ERROR_TOO_MANY_OPEN_FILES #define EACCES ERROR_ACCESS_DENIED #define EBADF ERROR_INVALID_HANDLE #define ENOMEM ERROR_NOT_ENOUGH_MEMORY #define EXDEV ERROR_NOT_SAME_DEVICE #define ENFILE ERROR_NO_MORE_FILES #define EROFS ERROR_WRITE_PROTECT #define ENOLCK ERROR_SHARING_BUFFER_EXCEEDED #define ENOSYS ERROR_NOT_SUPPORTED #define EEXIST ERROR_FILE_EXISTS #define EPERM ERROR_CANNOT_MAKE #define EINVAL ERROR_INVALID_PARAMETER #define EINTR ERROR_INVALID_AT_INTERRUPT_TIME #define EPIPE ERROR_BROKEN_PIPE #define ENOSPC ERROR_DISK_FULL #define ENOTEMPTY ERROR_DIR_NOT_EMPTY #define EBUSY ERROR_BUSY #define ENAMETOOLONG ERROR_FILENAME_EXCED_RANGE #define EAGAIN ERROR_MORE_DATA #define ENOTDIR ERROR_DIRECTORY #define ERANGE ERROR_ARITHMETIC_OVERFLOW #define ENXIO ERROR_FILE_INVALID #define EFAULT ERROR_PROCESS_ABORTED #define EIO ERROR_IO_DEVICE #define EDEADLOCK ERROR_POSSIBLE_DEADLOCK #define ENODEV ERROR_BAD_DEVICE /* Windows CE is missing more stuff that is pretty standard. */ #define strdup _strdup #define stricmp _stricmp #define strnicmp _strnicmp #define environ _dbus_wince_environ extern char *environ[]; #define getenv _dbus_wince_getenv char *getenv (const char *name); #define putenv _dbus_wince_putenv int putenv (char *str); #define clock _dbus_wince_clock clock_t clock (void); #define abort _dbus_wince_abort void abort (void); #define _S_IFMT 0170000 /* file type mask */ #define _S_IFDIR 0040000 /* directory */ #define _S_IFCHR 0020000 /* character special */ #define _S_IFIFO 0010000 /* pipe */ #define _S_IFREG 0100000 /* regular */ #define _S_IREAD 0000400 /* read permission, owner */ #define _S_IWRITE 0000200 /* write permission, owner */ #define _S_IEXEC 0000100 /* execute/search permission, owner */ #ifndef __OFF_T_DEFINED typedef long off_t; #define __OFF_T_DEFINED #endif #ifndef _INTPTR_T_DEFINED typedef int intptr_t; #define _INTPTR_T_DEFINED #endif #ifndef _UINTPTR_T_DEFINED typedef unsigned int uintptr_t; #define _UINTPTR_T_DEFINED #endif #ifndef _MAX_FNAME #define _MAX_FNAME 256 #endif #ifndef _IOFBF #define _IOFBF 0 #endif #ifndef _IOLBF #define _IOLBF 1 #endif #ifndef _IONBF #define _IONBF 2 #endif /* Windows CE is missing some Windows functions that we want. */ #define GetSystemTimeAsFileTime _dbus_wince_GetSystemTimeAsFileTime void GetSystemTimeAsFileTime (LPFILETIME ftp); #define _mbsrchr _dbus_wince_mbsrchr unsigned char* _mbsrchr (const unsigned char*, unsigned int); #define OpenFileMappingA _dbus_wince_OpenFileMappingA HANDLE OpenFileMappingA(DWORD,BOOL,LPCSTR); #define MoveFileExA _dbus_wince_MoveFileExA BOOL MoveFileExA(LPCSTR,LPCSTR,DWORD); #ifndef MOVEFILE_REPLACE_EXISTING #define MOVEFILE_REPLACE_EXISTING 0x00000001 #endif #define SetHandleInformation _dbus_wince_SetHandleInformation BOOL SetHandleInformation(HANDLE,DWORD,DWORD); #ifndef HANDLE_FLAG_INHERIT #define HANDLE_FLAG_INHERIT 0x01 #endif #ifndef HANDLE_FLAG_PROTECT #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x02 #endif #define SearchPathA _dbus_wince_SearchPathA DWORD SearchPathA(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*); /* Instead of emulating all functions needed for this, we replace the whole thing. */ dbus_bool_t _dbus_getsid(char **sid); #define LookupAccountNameW _dbus_wince_LookupAccountNameW BOOL LookupAccountNameW(LPCWSTR,LPCWSTR,PSID,PDWORD,LPWSTR,PDWORD,PSID_NAME_USE); #define IsValidSid _dbus_wince_IsValidSid BOOL IsValidSid(PSID); /* Windows CE does only have the UNICODE interfaces (FooW), but we want to use the ASCII interfaces (FooA). We implement them here. */ #define CreateFileA _dbus_wince_CreateFileA HANDLE CreateFileA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE); #define DeleteFileA _dbus_wince_DeleteFileA BOOL DeleteFileA(LPCSTR); #define GetFileAttributesA _dbus_wince_GetFileAttributesA DWORD GetFileAttributesA(LPCSTR); #define GetFileAttributesExA _dbus_wince_GetFileAttributesExA BOOL GetFileAttributesExA(LPCSTR,GET_FILEEX_INFO_LEVELS,PVOID); #define CreateFileMappingA _dbus_wince_CreateFileMappingA HANDLE CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCSTR); #define CreateDirectoryA _dbus_wince_CreateDirectoryA BOOL CreateDirectoryA(LPCSTR,LPSECURITY_ATTRIBUTES); #define RemoveDirectoryA _dbus_wince_RemoveDirectoryA BOOL RemoveDirectoryA(LPCSTR); #define FindFirstFileA _dbus_wince_FindFirstFileA HANDLE FindFirstFileA(LPCSTR,LPWIN32_FIND_DATAA); #define FindNextFileA _dbus_wince_FindNextFileA BOOL FindNextFileA(HANDLE,LPWIN32_FIND_DATAA); #define CreateMutexA _dbus_wince_CreateMutexA HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR); #define CreateProcessA _dbus_wince_CreateProcessA BOOL CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION); #ifndef CREATE_NO_WINDOW #define CREATE_NO_WINDOW 0x08000000 #endif #define RegOpenKeyExA _dbus_wince_RegOpenKeyExA LONG RegOpenKeyExA(HKEY,LPCSTR,DWORD,REGSAM,PHKEY); #define RegQueryValueExA _dbus_wince_RegQueryValueExA LONG WINAPI RegQueryValueExA(HKEY,LPCSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD); #define FormatMessageA _dbus_wince_FormatMessageA DWORD FormatMessageA(DWORD,PCVOID,DWORD,DWORD,LPSTR,DWORD,va_list*); #define GetModuleFileNameA _dbus_wince_GetModuleFileNameA DWORD GetModuleFileNameA(HINSTANCE,LPSTR,DWORD); #define GetTempPathA _dbus_wince_GetTempPathA DWORD GetTempPathA(DWORD,LPSTR); #define SHGetSpecialFolderPathA _dbus_wince_SHGetSpecialFolderPathA BOOL SHGetSpecialFolderPathA(HWND,LPSTR,int,BOOL); #define OutputDebugStringA _dbus_wince_OutputDebugStringA void OutputDebugStringA(LPCSTR); DBUS_END_DECLS #endif /* DBUS_SYSDEPS_WINCE_GLUE_H */ dbus-1.10.6/dbus/dbus-userdb.h0000644000175000017500000001417312602773110016070 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-userdb.h User database abstraction * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_USERDB_H #define DBUS_USERDB_H #include #ifdef DBUS_WIN #error "Don't include this on Windows" #endif DBUS_BEGIN_DECLS typedef struct DBusUserDatabase DBusUserDatabase; #ifdef DBUS_USERDB_INCLUDES_PRIVATE #include /** * Internals of DBusUserDatabase */ struct DBusUserDatabase { int refcount; /**< Reference count */ DBusHashTable *users; /**< Users in the database by UID */ DBusHashTable *groups; /**< Groups in the database by GID */ DBusHashTable *users_by_name; /**< Users in the database by name */ DBusHashTable *groups_by_name; /**< Groups in the database by name */ }; DBusUserDatabase* _dbus_user_database_new (void); DBusUserDatabase* _dbus_user_database_ref (DBusUserDatabase *db); void _dbus_user_database_flush (DBusUserDatabase *db); void _dbus_user_database_unref (DBusUserDatabase *db); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_user_database_get_uid (DBusUserDatabase *db, dbus_uid_t uid, const DBusUserInfo **info, DBusError *error); dbus_bool_t _dbus_user_database_get_gid (DBusUserDatabase *db, dbus_gid_t gid, const DBusGroupInfo **info, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_user_database_get_username (DBusUserDatabase *db, const DBusString *username, const DBusUserInfo **info, DBusError *error); dbus_bool_t _dbus_user_database_get_groupname (DBusUserDatabase *db, const DBusString *groupname, const DBusGroupInfo **info, DBusError *error); DBUS_PRIVATE_EXPORT DBusUserInfo* _dbus_user_database_lookup (DBusUserDatabase *db, dbus_uid_t uid, const DBusString *username, DBusError *error); DBUS_PRIVATE_EXPORT DBusGroupInfo* _dbus_user_database_lookup_group (DBusUserDatabase *db, dbus_gid_t gid, const DBusString *groupname, DBusError *error); DBUS_PRIVATE_EXPORT void _dbus_user_info_free_allocated (DBusUserInfo *info); DBUS_PRIVATE_EXPORT void _dbus_group_info_free_allocated (DBusGroupInfo *info); #endif /* DBUS_USERDB_INCLUDES_PRIVATE */ DBUS_PRIVATE_EXPORT DBusUserDatabase* _dbus_user_database_get_system (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_user_database_lock_system (void) _DBUS_GNUC_WARN_UNUSED_RESULT; DBUS_PRIVATE_EXPORT void _dbus_user_database_unlock_system (void); void _dbus_user_database_flush_system (void); dbus_bool_t _dbus_get_user_id (const DBusString *username, dbus_uid_t *uid); dbus_bool_t _dbus_get_group_id (const DBusString *group_name, dbus_gid_t *gid); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_get_user_id_and_primary_group (const DBusString *username, dbus_uid_t *uid_p, dbus_gid_t *gid_p); dbus_bool_t _dbus_credentials_from_uid (dbus_uid_t user_id, DBusCredentials *credentials); dbus_bool_t _dbus_groups_from_uid (dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_is_console_user (dbus_uid_t uid, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_is_a_number (const DBusString *str, unsigned long *num); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_username_from_current_process (const DBusString **username); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_homedir_from_current_process (const DBusString **homedir); dbus_bool_t _dbus_homedir_from_username (const DBusString *username, DBusString *homedir); dbus_bool_t _dbus_homedir_from_uid (dbus_uid_t uid, DBusString *homedir); DBUS_END_DECLS #endif /* DBUS_USERDB_H */ dbus-1.10.6/dbus/dbus-userdb.c0000644000175000017500000004150412602773110016061 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-userdb.c User database abstraction * * Copyright (C) 2003, 2004 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #define DBUS_USERDB_INCLUDES_PRIVATE 1 #include "dbus-userdb.h" #include "dbus-hash.h" #include "dbus-test.h" #include "dbus-internals.h" #include "dbus-protocol.h" #include "dbus-credentials.h" #include /** * @addtogroup DBusInternalsUtils * @{ */ /** * Frees the given #DBusUserInfo's members with _dbus_user_info_free() * and also calls dbus_free() on the block itself * * @param info the info */ void _dbus_user_info_free_allocated (DBusUserInfo *info) { if (info == NULL) /* hash table will pass NULL */ return; _dbus_user_info_free (info); dbus_free (info); } /** * Frees the given #DBusGroupInfo's members with _dbus_group_info_free() * and also calls dbus_free() on the block itself * * @param info the info */ void _dbus_group_info_free_allocated (DBusGroupInfo *info) { if (info == NULL) /* hash table will pass NULL */ return; _dbus_group_info_free (info); dbus_free (info); } /** * Frees the members of info * (but not info itself) * @param info the user info struct */ void _dbus_user_info_free (DBusUserInfo *info) { dbus_free (info->group_ids); dbus_free (info->username); dbus_free (info->homedir); } /** * Frees the members of info (but not info itself). * * @param info the group info */ void _dbus_group_info_free (DBusGroupInfo *info) { dbus_free (info->groupname); } /** * Checks if a given string is actually a number * and converts it if it is * * @param str the string to check * @param num the memory location of the unsigned long to fill in * @returns TRUE if str is a number and num is filled in */ dbus_bool_t _dbus_is_a_number (const DBusString *str, unsigned long *num) { int end; if (_dbus_string_parse_uint (str, 0, num, &end) && end == _dbus_string_get_length (str)) return TRUE; else return FALSE; } /** * Looks up a uid or username in the user database. Only one of name * or UID can be provided. There are wrapper functions for this that * are better to use, this one does no locking or anything on the * database and otherwise sort of sucks. * * @param db the database * @param uid the user ID or #DBUS_UID_UNSET * @param username username or #NULL * @param error error to fill in * @returns the entry in the database */ DBusUserInfo* _dbus_user_database_lookup (DBusUserDatabase *db, dbus_uid_t uid, const DBusString *username, DBusError *error) { DBusUserInfo *info; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (uid != DBUS_UID_UNSET || username != NULL); /* See if the username is really a number */ if (uid == DBUS_UID_UNSET) { unsigned long n; if (_dbus_is_a_number (username, &n)) uid = n; } if (uid != DBUS_UID_UNSET) info = _dbus_hash_table_lookup_uintptr (db->users, uid); else info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username)); if (info) { _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n", info->uid); return info; } else { if (uid != DBUS_UID_UNSET) _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", uid); else _dbus_verbose ("No cache for user \"%s\"\n", _dbus_string_get_const_data (username)); info = dbus_new0 (DBusUserInfo, 1); if (info == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (uid != DBUS_UID_UNSET) { if (!_dbus_user_info_fill_uid (info, uid, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_user_info_free_allocated (info); return NULL; } } else { if (!_dbus_user_info_fill (info, username, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_user_info_free_allocated (info); return NULL; } } /* be sure we don't use these after here */ uid = DBUS_UID_UNSET; username = NULL; /* insert into hash */ if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_user_info_free_allocated (info); return NULL; } if (!_dbus_hash_table_insert_string (db->users_by_name, info->username, info)) { _dbus_hash_table_remove_uintptr (db->users, info->uid); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } return info; } } static dbus_bool_t database_locked = FALSE; static DBusUserDatabase *system_db = NULL; static DBusString process_username; static DBusString process_homedir; static void shutdown_system_db (void *data) { if (system_db != NULL) _dbus_user_database_unref (system_db); system_db = NULL; _dbus_string_free (&process_username); _dbus_string_free (&process_homedir); } static dbus_bool_t init_system_db (void) { _dbus_assert (database_locked); if (system_db == NULL) { DBusError error = DBUS_ERROR_INIT; const DBusUserInfo *info; system_db = _dbus_user_database_new (); if (system_db == NULL) return FALSE; if (!_dbus_user_database_get_uid (system_db, _dbus_getuid (), &info, &error)) { _dbus_user_database_unref (system_db); system_db = NULL; if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); return FALSE; } else { /* This really should not happen. */ _dbus_warn ("Could not get password database information for UID of current process: %s\n", error.message); dbus_error_free (&error); return FALSE; } } if (!_dbus_string_init (&process_username)) { _dbus_user_database_unref (system_db); system_db = NULL; return FALSE; } if (!_dbus_string_init (&process_homedir)) { _dbus_string_free (&process_username); _dbus_user_database_unref (system_db); system_db = NULL; return FALSE; } if (!_dbus_string_append (&process_username, info->username) || !_dbus_string_append (&process_homedir, info->homedir) || !_dbus_register_shutdown_func (shutdown_system_db, NULL)) { _dbus_string_free (&process_username); _dbus_string_free (&process_homedir); _dbus_user_database_unref (system_db); system_db = NULL; return FALSE; } } return TRUE; } /** * Locks global system user database. */ dbus_bool_t _dbus_user_database_lock_system (void) { if (_DBUS_LOCK (system_users)) { database_locked = TRUE; return TRUE; } else { return FALSE; } } /** * Unlocks global system user database. */ void _dbus_user_database_unlock_system (void) { database_locked = FALSE; _DBUS_UNLOCK (system_users); } /** * Gets the system global user database; * must be called with lock held (_dbus_user_database_lock_system()). * * @returns the database or #NULL if no memory */ DBusUserDatabase* _dbus_user_database_get_system (void) { _dbus_assert (database_locked); init_system_db (); return system_db; } /** * Flushes the system global user database; */ void _dbus_user_database_flush_system (void) { if (!_dbus_user_database_lock_system ()) { /* nothing to flush */ return; } if (system_db != NULL) _dbus_user_database_flush (system_db); _dbus_user_database_unlock_system (); } /** * Gets username of user owning current process. The returned string * is valid until dbus_shutdown() is called. * * @param username place to store pointer to username * @returns #FALSE if no memory */ dbus_bool_t _dbus_username_from_current_process (const DBusString **username) { if (!_dbus_user_database_lock_system ()) return FALSE; if (!init_system_db ()) { _dbus_user_database_unlock_system (); return FALSE; } *username = &process_username; _dbus_user_database_unlock_system (); return TRUE; } /** * Gets homedir of user owning current process. The returned string * is valid until dbus_shutdown() is called. * * @param homedir place to store pointer to homedir * @returns #FALSE if no memory */ dbus_bool_t _dbus_homedir_from_current_process (const DBusString **homedir) { if (!_dbus_user_database_lock_system ()) return FALSE; if (!init_system_db ()) { _dbus_user_database_unlock_system (); return FALSE; } *homedir = &process_homedir; _dbus_user_database_unlock_system (); return TRUE; } /** * Gets the home directory for the given user. * * @param username the username * @param homedir string to append home directory to * @returns #TRUE if user existed and we appended their homedir */ dbus_bool_t _dbus_homedir_from_username (const DBusString *username, DBusString *homedir) { DBusUserDatabase *db; const DBusUserInfo *info; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_username (db, username, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_string_append (homedir, info->homedir)) { _dbus_user_database_unlock_system (); return FALSE; } _dbus_user_database_unlock_system (); return TRUE; } /** * Gets the home directory for the given user. * * @param uid the uid * @param homedir string to append home directory to * @returns #TRUE if user existed and we appended their homedir */ dbus_bool_t _dbus_homedir_from_uid (dbus_uid_t uid, DBusString *homedir) { DBusUserDatabase *db; const DBusUserInfo *info; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_uid (db, uid, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_string_append (homedir, info->homedir)) { _dbus_user_database_unlock_system (); return FALSE; } _dbus_user_database_unlock_system (); return TRUE; } /** * Adds the credentials corresponding to the given username. * * Used among other purposes to parses a desired identity provided * from a client in the auth protocol. On UNIX this means parsing a * UID, on Windows probably parsing an SID string. * * @todo this is broken because it treats OOM and parse error * the same way. Needs a #DBusError. * * @param credentials credentials to fill in * @param username the username * @returns #TRUE if the username existed and we got some credentials */ dbus_bool_t _dbus_credentials_add_from_user (DBusCredentials *credentials, const DBusString *username) { DBusUserDatabase *db; const DBusUserInfo *info; /* FIXME: this can't distinguish ENOMEM from other errors */ if (!_dbus_user_database_lock_system ()) return FALSE; db = _dbus_user_database_get_system (); if (db == NULL) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_user_database_get_username (db, username, &info, NULL)) { _dbus_user_database_unlock_system (); return FALSE; } if (!_dbus_credentials_add_unix_uid(credentials, info->uid)) { _dbus_user_database_unlock_system (); return FALSE; } _dbus_user_database_unlock_system (); return TRUE; } /** * Creates a new user database object used to look up and * cache user information. * @returns new database, or #NULL on out of memory */ DBusUserDatabase* _dbus_user_database_new (void) { DBusUserDatabase *db; db = dbus_new0 (DBusUserDatabase, 1); if (db == NULL) return NULL; db->refcount = 1; db->users = _dbus_hash_table_new (DBUS_HASH_UINTPTR, NULL, (DBusFreeFunction) _dbus_user_info_free_allocated); if (db->users == NULL) goto failed; db->groups = _dbus_hash_table_new (DBUS_HASH_UINTPTR, NULL, (DBusFreeFunction) _dbus_group_info_free_allocated); if (db->groups == NULL) goto failed; db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, NULL); if (db->users_by_name == NULL) goto failed; db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, NULL); if (db->groups_by_name == NULL) goto failed; return db; failed: _dbus_user_database_unref (db); return NULL; } /** * Flush all information out of the user database. */ void _dbus_user_database_flush (DBusUserDatabase *db) { _dbus_hash_table_remove_all(db->users_by_name); _dbus_hash_table_remove_all(db->groups_by_name); _dbus_hash_table_remove_all(db->users); _dbus_hash_table_remove_all(db->groups); } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Increments refcount of user database. * @param db the database * @returns the database */ DBusUserDatabase * _dbus_user_database_ref (DBusUserDatabase *db) { _dbus_assert (db->refcount > 0); db->refcount += 1; return db; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** * Decrements refcount of user database. * @param db the database */ void _dbus_user_database_unref (DBusUserDatabase *db) { _dbus_assert (db->refcount > 0); db->refcount -= 1; if (db->refcount == 0) { if (db->users) _dbus_hash_table_unref (db->users); if (db->groups) _dbus_hash_table_unref (db->groups); if (db->users_by_name) _dbus_hash_table_unref (db->users_by_name); if (db->groups_by_name) _dbus_hash_table_unref (db->groups_by_name); dbus_free (db); } } /** * Gets the user information for the given UID, * returned user info should not be freed. * * @param db user database * @param uid the user ID * @param info return location for const ref to user info * @param error error location * @returns #FALSE if error is set */ dbus_bool_t _dbus_user_database_get_uid (DBusUserDatabase *db, dbus_uid_t uid, const DBusUserInfo **info, DBusError *error) { *info = _dbus_user_database_lookup (db, uid, NULL, error); return *info != NULL; } /** * Gets the user information for the given username. * * @param db user database * @param username the user name * @param info return location for const ref to user info * @param error error location * @returns #FALSE if error is set */ dbus_bool_t _dbus_user_database_get_username (DBusUserDatabase *db, const DBusString *username, const DBusUserInfo **info, DBusError *error) { *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error); return *info != NULL; } /** @} */ /* Tests in dbus-userdb-util.c */ dbus-1.10.6/dbus/dbus-transport-unix.h0000644000175000017500000000252612602773110017620 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-unix.h UNIX socket subclasses of DBusTransport * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TRANSPORT_UNIX_H #define DBUS_TRANSPORT_UNIX_H #include DBUS_BEGIN_DECLS DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error); DBUS_END_DECLS #endif /* DBUS_TRANSPORT_UNIX_H */ dbus-1.10.6/dbus/dbus-transport-unix.c0000644000175000017500000003000412602773110017603 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-transport-unix.h" #include "dbus-transport-socket.h" #include "dbus-transport-protected.h" #include "dbus-watch.h" #include "dbus-sysdeps-unix.h" #include "dbus-test.h" /** * @defgroup DBusTransportUnix DBusTransport implementations for UNIX * @ingroup DBusInternals * @brief Implementation details of DBusTransport on UNIX * * @{ */ /** * Creates a new transport for the given Unix domain socket * path. This creates a client-side of a transport. * * @todo once we add a way to escape paths in a dbus * address, this function needs to do escaping. * * @param path the path to the domain socket. * @param abstract #TRUE to use abstract socket namespace * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error) { DBusSocket fd = DBUS_SOCKET_INIT; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_string_append (&address, path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } fd.fd = _dbus_connect_unix_socket (path, abstract, error); if (fd.fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_0; } _dbus_verbose ("Successfully connected to unix socket %s\n", path); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_1; } _dbus_string_free (&address); return transport; failed_1: _dbus_close_socket (fd, NULL); failed_0: _dbus_string_free (&address); return NULL; } /** * Creates a new transport for the given binary and arguments. This * creates a client-side of a transport. The process will be forked * off and executed with stdin/stdout connected to a local AF_UNIX * socket. * * @param path the path to the domain socket. * @param argv Parameters list * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* _dbus_transport_new_for_exec (const char *path, char *const argv[], DBusError *error) { DBusSocket fd = DBUS_SOCKET_INIT; DBusTransport *transport; DBusString address; unsigned i; char *escaped; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } escaped = dbus_address_escape_value (path); if (!escaped) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } if (!_dbus_string_append (&address, "unixexec:path=") || !_dbus_string_append (&address, escaped)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_free (escaped); goto failed; } dbus_free (escaped); if (argv) { for (i = 0; argv[i]; i++) { dbus_bool_t success; escaped = dbus_address_escape_value (argv[i]); if (!escaped) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } success = _dbus_string_append_printf (&address, ",argv%u=%s", i, escaped); dbus_free (escaped); if (!success) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } } } fd.fd = _dbus_connect_exec (path, argv, error); if (fd.fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed; } _dbus_verbose ("Successfully connected to process %s\n", path); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } _dbus_string_free (&address); return transport; failed: if (fd.fd >= 0) _dbus_close_socket (fd, NULL); _dbus_string_free (&address); return NULL; } /** * Opens platform specific transport types. * * @param entry the address entry to try opening * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "unix") == 0) { const char *path = dbus_address_entry_get_value (entry, "path"); const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); const char *abstract = dbus_address_entry_get_value (entry, "abstract"); if (tmpdir != NULL) { _dbus_set_bad_address (error, NULL, NULL, "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path == NULL && abstract == NULL) { _dbus_set_bad_address (error, "unix", "path or abstract", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path != NULL && abstract != NULL) { _dbus_set_bad_address (error, NULL, NULL, "can't specify both \"path\" and \"abstract\" options in an address"); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path) *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, error); else *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else if (strcmp (method, "unixexec") == 0) { const char *path; unsigned i; char **argv; path = dbus_address_entry_get_value (entry, "path"); if (path == NULL) { _dbus_set_bad_address (error, NULL, NULL, "No process path specified"); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } /* First count argv arguments */ for (i = 1; ; i++) { char t[4+20+1]; /* "argv" plus space for a formatted base 10 64bit integer, plus NUL */ snprintf (t, sizeof(t), "argv%u", i); if (!dbus_address_entry_get_value (entry, t)) break; } /* Allocate string array */ argv = dbus_new0 (char*, i+1); if (!argv) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } /* Fill in string array */ for (i = 0; ; i++) { char t[4+20+1]; const char *p; snprintf (t, sizeof(t), "argv%u", i); p = dbus_address_entry_get_value (entry, t); if (!p) { if (i == 0) /* If argv0 isn't specified, fill in the path instead */ p = path; else break; } argv[i] = _dbus_strdup (p); if (!argv[i]) { dbus_free_string_array (argv); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } } *transport_p = _dbus_transport_new_for_exec (path, argv, error); dbus_free_string_array (argv); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } #ifdef DBUS_ENABLE_LAUNCHD else if (strcmp (method, "launchd") == 0) { DBusError tmp_error = DBUS_ERROR_INIT; const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); const char *launchd_socket; DBusString socket_path; dbus_bool_t valid_socket; if (!_dbus_string_init (&socket_path)) { _DBUS_SET_OOM (error); return FALSE; } if (launchd_env_var == NULL) { _dbus_set_bad_address (error, "launchd", "env", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error); if (dbus_error_is_set(error)) { _dbus_string_free(&socket_path); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } if (!valid_socket) { dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS, "launchd's env var %s does not exist", launchd_env_var); dbus_error_free(error); dbus_move_error(&tmp_error, error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } launchd_socket = _dbus_string_get_const_data(&socket_path); *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } #endif else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS dbus_bool_t _dbus_transport_unix_test (void) { DBusConnection *c; DBusError error; dbus_bool_t ret; const char *address; dbus_error_init (&error); c = dbus_connection_open ("unixexec:argv0=false,argv1=foobar,path=/bin/false", &error); _dbus_assert (c != NULL); _dbus_assert (!dbus_error_is_set (&error)); address = _dbus_connection_get_address (c); _dbus_assert (address != NULL); /* Let's see if the address got parsed, reordered and formatted correctly */ ret = strcmp (address, "unixexec:path=/bin/false,argv0=false,argv1=foobar") == 0; dbus_connection_unref (c); return ret; } #endif dbus-1.10.6/dbus/dbus-sysdeps-pthread.c0000644000175000017500000001701112602773110017710 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-threads.h" #include #include #include #ifdef HAVE_ERRNO_H #include #endif #include #ifdef HAVE_MONOTONIC_CLOCK /* Whether we have a "monotonic" clock; i.e. a clock not affected by * changes in system time. * This is initialized once in check_monotonic_clock below. * https://bugs.freedesktop.org/show_bug.cgi?id=18121 */ static dbus_bool_t have_monotonic_clock = 0; #endif struct DBusRMutex { pthread_mutex_t lock; /**< the lock */ }; struct DBusCMutex { pthread_mutex_t lock; /**< the lock */ }; struct DBusCondVar { pthread_cond_t cond; /**< the condition */ }; #define DBUS_MUTEX(m) ((DBusMutex*) m) #define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m) #define DBUS_COND_VAR(c) ((DBusCondVar*) c) #define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c) #ifdef DBUS_DISABLE_ASSERT /* (tmp != 0) is a no-op usage to silence compiler */ #define PTHREAD_CHECK(func_name, result_or_call) \ do { int tmp = (result_or_call); if (tmp != 0) {;} } while (0) #else #define PTHREAD_CHECK(func_name, result_or_call) do { \ int tmp = (result_or_call); \ if (tmp != 0) { \ _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n", \ func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME); \ } \ } while (0) #endif /* !DBUS_DISABLE_ASSERT */ DBusCMutex * _dbus_platform_cmutex_new (void) { DBusCMutex *pmutex; int result; pmutex = dbus_new (DBusCMutex, 1); if (pmutex == NULL) return NULL; result = pthread_mutex_init (&pmutex->lock, NULL); if (result == ENOMEM || result == EAGAIN) { dbus_free (pmutex); return NULL; } else { PTHREAD_CHECK ("pthread_mutex_init", result); } return pmutex; } DBusRMutex * _dbus_platform_rmutex_new (void) { DBusRMutex *pmutex; pthread_mutexattr_t mutexattr; int result; pmutex = dbus_new (DBusRMutex, 1); if (pmutex == NULL) return NULL; pthread_mutexattr_init (&mutexattr); pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE); result = pthread_mutex_init (&pmutex->lock, &mutexattr); pthread_mutexattr_destroy (&mutexattr); if (result == ENOMEM || result == EAGAIN) { dbus_free (pmutex); return NULL; } else { PTHREAD_CHECK ("pthread_mutex_init", result); } return pmutex; } void _dbus_platform_cmutex_free (DBusCMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); dbus_free (mutex); } void _dbus_platform_rmutex_free (DBusRMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); dbus_free (mutex); } void _dbus_platform_cmutex_lock (DBusCMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); } void _dbus_platform_rmutex_lock (DBusRMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); } void _dbus_platform_cmutex_unlock (DBusCMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); } void _dbus_platform_rmutex_unlock (DBusRMutex *mutex) { PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); } DBusCondVar * _dbus_platform_condvar_new (void) { DBusCondVar *pcond; pthread_condattr_t attr; int result; pcond = dbus_new (DBusCondVar, 1); if (pcond == NULL) return NULL; pthread_condattr_init (&attr); #ifdef HAVE_MONOTONIC_CLOCK if (have_monotonic_clock) pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); #endif result = pthread_cond_init (&pcond->cond, &attr); pthread_condattr_destroy (&attr); if (result == EAGAIN || result == ENOMEM) { dbus_free (pcond); return NULL; } else { PTHREAD_CHECK ("pthread_cond_init", result); } return pcond; } void _dbus_platform_condvar_free (DBusCondVar *cond) { PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&cond->cond)); dbus_free (cond); } void _dbus_platform_condvar_wait (DBusCondVar *cond, DBusCMutex *mutex) { PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&cond->cond, &mutex->lock)); } dbus_bool_t _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, DBusCMutex *mutex, int timeout_milliseconds) { struct timeval time_now; struct timespec end_time; int result; #ifdef HAVE_MONOTONIC_CLOCK if (have_monotonic_clock) { struct timespec monotonic_timer; clock_gettime (CLOCK_MONOTONIC,&monotonic_timer); time_now.tv_sec = monotonic_timer.tv_sec; time_now.tv_usec = monotonic_timer.tv_nsec / 1000; } else /* This else falls through to gettimeofday */ #endif gettimeofday (&time_now, NULL); end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000; end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000; if (end_time.tv_nsec > 1000*1000*1000) { end_time.tv_sec += 1; end_time.tv_nsec -= 1000*1000*1000; } result = pthread_cond_timedwait (&cond->cond, &mutex->lock, &end_time); if (result != ETIMEDOUT) { PTHREAD_CHECK ("pthread_cond_timedwait", result); } /* return true if we did not time out */ return result != ETIMEDOUT; } void _dbus_platform_condvar_wake_one (DBusCondVar *cond) { PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&cond->cond)); } static void check_monotonic_clock (void) { #ifdef HAVE_MONOTONIC_CLOCK struct timespec dummy; if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0) have_monotonic_clock = TRUE; #endif } dbus_bool_t _dbus_threads_init_platform_specific (void) { /* These have static variables, and we need to handle both the case * where dbus_threads_init() has been called and when it hasn't; * so initialize them before any threads are allowed to enter. */ check_monotonic_clock (); (void) _dbus_check_setuid (); return TRUE; } static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; void _dbus_threads_lock_platform_specific (void) { pthread_mutex_lock (&init_mutex); } void _dbus_threads_unlock_platform_specific (void) { pthread_mutex_unlock (&init_mutex); } dbus-1.10.6/dbus/dbus-sysdeps-unix.h0000644000175000017500000001303512624704607017264 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-unix.h UNIX-specific wrappers around system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SYSDEPS_UNIX_H #define DBUS_SYSDEPS_UNIX_H #include #ifdef DBUS_WIN #error "Don't include this on Windows" #endif DBUS_BEGIN_DECLS /** * @defgroup DBusSysdepsUnix UNIX-specific internal API * @ingroup DBusInternals * @brief Internal system-dependent API available on UNIX only * @{ */ DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_close (int fd, DBusError *error); DBUS_PRIVATE_EXPORT int _dbus_dup (int fd, DBusError *error); DBUS_PRIVATE_EXPORT int _dbus_read (int fd, DBusString *buffer, int count); int _dbus_write (int fd, const DBusString *buffer, int start, int len); int _dbus_write_two (int fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2); int _dbus_connect_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error); int _dbus_listen_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error); int _dbus_connect_exec (const char *path, char *const argv[], DBusError *error); int _dbus_listen_systemd_sockets (DBusSocket **fd, DBusError *error); dbus_bool_t _dbus_read_credentials (int client_fd, DBusCredentials *credentials, DBusError *error); dbus_bool_t _dbus_send_credentials (int server_fd, DBusError *error); dbus_bool_t _dbus_lookup_launchd_socket (DBusString *socket_path, const char *launchd_env_var, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_lookup_user_bus (dbus_bool_t *supported, DBusString *address, DBusError *error); /** Information about a UNIX user */ typedef struct DBusUserInfo DBusUserInfo; /** Information about a UNIX group */ typedef struct DBusGroupInfo DBusGroupInfo; /** * Information about a UNIX user */ struct DBusUserInfo { dbus_uid_t uid; /**< UID */ dbus_gid_t primary_gid; /**< GID */ dbus_gid_t *group_ids; /**< Groups IDs, *including* above primary group */ int n_group_ids; /**< Size of group IDs array */ char *username; /**< Username */ char *homedir; /**< Home directory */ }; /** * Information about a UNIX group */ struct DBusGroupInfo { dbus_gid_t gid; /**< GID */ char *groupname; /**< Group name */ }; dbus_bool_t _dbus_user_info_fill (DBusUserInfo *info, const DBusString *username, DBusError *error); dbus_bool_t _dbus_user_info_fill_uid (DBusUserInfo *info, dbus_uid_t uid, DBusError *error); void _dbus_user_info_free (DBusUserInfo *info); dbus_bool_t _dbus_group_info_fill (DBusGroupInfo *info, const DBusString *groupname, DBusError *error); dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info, dbus_gid_t gid, DBusError *error); void _dbus_group_info_free (DBusGroupInfo *info); DBUS_PRIVATE_EXPORT dbus_uid_t _dbus_geteuid (void); dbus_bool_t _dbus_parse_uid (const DBusString *uid_str, dbus_uid_t *uid); DBUS_PRIVATE_EXPORT void _dbus_close_all (void); dbus_bool_t _dbus_append_address_from_socket (DBusSocket fd, DBusString *address, DBusError *error); DBUS_PRIVATE_EXPORT void _dbus_fd_set_close_on_exec (int fd); /** @} */ DBUS_END_DECLS #endif /* DBUS_SYSDEPS_UNIX_H */ dbus-1.10.6/dbus/dbus-sysdeps-unix.c0000644000175000017500000035420712602773110017257 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-file.h" #include "dbus-transport.h" #include "dbus-string.h" #include "dbus-userdb.h" #include "dbus-list.h" #include "dbus-credentials.h" #include "dbus-nonce.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_WRITEV #include #endif #ifdef HAVE_POLL #include #endif #ifdef HAVE_BACKTRACE #include #endif #ifdef HAVE_GETPEERUCRED #include #endif #ifdef HAVE_ALLOCA_H #include #endif #ifdef HAVE_ADT #include #endif #ifdef HAVE_SYSTEMD #include #endif #if !DBUS_USE_SYNC #include #endif #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0 #endif #ifndef HAVE_SOCKLEN_T #define socklen_t int #endif #if defined (__sun) || defined (__sun__) /* * CMS_SPACE etc. definitions for Solaris < 10, based on * http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html * via * http://wiki.opencsw.org/porting-faq#toc10 * * These are only redefined for Solaris, for now: if your OS needs these too, * please file a bug. (Or preferably, improve your OS so they're not needed.) */ # ifndef CMSG_ALIGN # ifdef __sun__ # define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len) # else /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */ # define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \ ~(sizeof (long) - 1)) # endif # endif # ifndef CMSG_SPACE # define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \ CMSG_ALIGN (len)) # endif # ifndef CMSG_LEN # define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) # endif #endif /* Solaris */ static dbus_bool_t _dbus_set_fd_nonblocking (int fd, DBusError *error); static dbus_bool_t _dbus_open_socket (int *fd_p, int domain, int type, int protocol, DBusError *error) { #ifdef SOCK_CLOEXEC dbus_bool_t cloexec_done; *fd_p = socket (domain, type | SOCK_CLOEXEC, protocol); cloexec_done = *fd_p >= 0; /* Check if kernel seems to be too old to know SOCK_CLOEXEC */ if (*fd_p < 0 && (errno == EINVAL || errno == EPROTOTYPE)) #endif { *fd_p = socket (domain, type, protocol); } if (*fd_p >= 0) { #ifdef SOCK_CLOEXEC if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec(*fd_p); } _dbus_verbose ("socket fd %d opened\n", *fd_p); return TRUE; } else { dbus_set_error(error, _dbus_error_from_errno (errno), "Failed to open socket: %s", _dbus_strerror (errno)); return FALSE; } } /** * Opens a UNIX domain socket (as in the socket() call). * Does not bind the socket. * * This will set FD_CLOEXEC for the socket returned * * @param fd return location for socket descriptor * @param error return location for an error * @returns #FALSE if error is set */ static dbus_bool_t _dbus_open_unix_socket (int *fd, DBusError *error) { return _dbus_open_socket(fd, PF_UNIX, SOCK_STREAM, 0, error); } /** * Closes a socket. Should not be used on non-socket * file descriptors or handles. * * @param fd the socket * @param error return location for an error * @returns #FALSE if error is set */ dbus_bool_t _dbus_close_socket (DBusSocket fd, DBusError *error) { return _dbus_close (fd.fd, error); } /** * Like _dbus_read(), but only works on sockets so is * available on Windows. * * @param fd the socket * @param buffer string to append data to * @param count max amount of data to read * @returns number of bytes appended to the string */ int _dbus_read_socket (DBusSocket fd, DBusString *buffer, int count) { return _dbus_read (fd.fd, buffer, count); } /** * Like _dbus_write(), but only supports sockets * and is thus available on Windows. * * @param fd the file descriptor to write * @param buffer the buffer to write data from * @param start the first byte in the buffer to write * @param len the number of bytes to try to write * @returns the number of bytes written or -1 on error */ int _dbus_write_socket (DBusSocket fd, const DBusString *buffer, int start, int len) { #if HAVE_DECL_MSG_NOSIGNAL const char *data; int bytes_written; data = _dbus_string_get_const_data_len (buffer, start, len); again: bytes_written = send (fd.fd, data, len, MSG_NOSIGNAL); if (bytes_written < 0 && errno == EINTR) goto again; return bytes_written; #else return _dbus_write (fd.fd, buffer, start, len); #endif } /** * Like _dbus_read_socket() but also tries to read unix fds from the * socket. When there are more fds to read than space in the array * passed this function will fail with ENOSPC. * * @param fd the socket * @param buffer string to append data to * @param count max amount of data to read * @param fds array to place read file descriptors in * @param n_fds on input space in fds array, on output how many fds actually got read * @returns number of bytes appended to string */ int _dbus_read_socket_with_unix_fds (DBusSocket fd, DBusString *buffer, int count, int *fds, int *n_fds) { #ifndef HAVE_UNIX_FD_PASSING int r; if ((r = _dbus_read_socket(fd, buffer, count)) < 0) return r; *n_fds = 0; return r; #else int bytes_read; int start; struct msghdr m; struct iovec iov; _dbus_assert (count >= 0); _dbus_assert (*n_fds >= 0); start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) { errno = ENOMEM; return -1; } _DBUS_ZERO(iov); iov.iov_base = _dbus_string_get_data_len (buffer, start, count); iov.iov_len = count; _DBUS_ZERO(m); m.msg_iov = &iov; m.msg_iovlen = 1; /* Hmm, we have no clue how long the control data will actually be that is queued for us. The least we can do is assume that the caller knows. Hence let's make space for the number of fds that we shall read at max plus the cmsg header. */ m.msg_controllen = CMSG_SPACE(*n_fds * sizeof(int)); /* It's probably safe to assume that systems with SCM_RIGHTS also know alloca() */ m.msg_control = alloca(m.msg_controllen); memset(m.msg_control, 0, m.msg_controllen); /* Do not include the padding at the end when we tell the kernel * how much we're willing to receive. This avoids getting * the padding filled with additional fds that we weren't expecting, * if a (potentially malicious) sender included them. (fd.o #83622) */ m.msg_controllen = CMSG_LEN (*n_fds * sizeof(int)); again: bytes_read = recvmsg (fd.fd, &m, 0 #ifdef MSG_CMSG_CLOEXEC |MSG_CMSG_CLOEXEC #endif ); if (bytes_read < 0) { if (errno == EINTR) goto again; else { /* put length back (note that this doesn't actually realloc anything) */ _dbus_string_set_length (buffer, start); return -1; } } else { struct cmsghdr *cm; dbus_bool_t found = FALSE; if (m.msg_flags & MSG_CTRUNC) { /* Hmm, apparently the control data was truncated. The bad thing is that we might have completely lost a couple of fds without chance to recover them. Hence let's treat this as a serious error. */ errno = ENOSPC; _dbus_string_set_length (buffer, start); return -1; } for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { size_t i; int *payload = (int *) CMSG_DATA (cm); size_t payload_len_bytes = (cm->cmsg_len - CMSG_LEN (0)); size_t payload_len_fds = payload_len_bytes / sizeof (int); size_t fds_to_use; /* Every non-negative int fits in a size_t without truncation, * and we already know that *n_fds is non-negative, so * casting (size_t) *n_fds is OK */ _DBUS_STATIC_ASSERT (sizeof (size_t) >= sizeof (int)); if (_DBUS_LIKELY (payload_len_fds <= (size_t) *n_fds)) { /* The fds in the payload will fit in our buffer */ fds_to_use = payload_len_fds; } else { /* Too many fds in the payload. This shouldn't happen * any more because we're setting m.msg_controllen to * the exact number we can accept, but be safe and * truncate. */ fds_to_use = (size_t) *n_fds; /* Close the excess fds to avoid DoS: if they stayed open, * someone could send us an extra fd per message * and we'd eventually run out. */ for (i = fds_to_use; i < payload_len_fds; i++) { close (payload[i]); } } memcpy (fds, payload, fds_to_use * sizeof (int)); found = TRUE; /* This cannot overflow because we have chosen fds_to_use * to be <= *n_fds */ *n_fds = (int) fds_to_use; /* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually worked, hence we need to go through this list and set CLOEXEC everywhere in any case */ for (i = 0; i < fds_to_use; i++) _dbus_fd_set_close_on_exec(fds[i]); break; } if (!found) *n_fds = 0; /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); #if 0 if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif return bytes_read; } #endif } int _dbus_write_socket_with_unix_fds(DBusSocket fd, const DBusString *buffer, int start, int len, const int *fds, int n_fds) { #ifndef HAVE_UNIX_FD_PASSING if (n_fds > 0) { errno = ENOTSUP; return -1; } return _dbus_write_socket(fd, buffer, start, len); #else return _dbus_write_socket_with_unix_fds_two(fd, buffer, start, len, NULL, 0, 0, fds, n_fds); #endif } int _dbus_write_socket_with_unix_fds_two(DBusSocket fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2, const int *fds, int n_fds) { #ifndef HAVE_UNIX_FD_PASSING if (n_fds > 0) { errno = ENOTSUP; return -1; } return _dbus_write_socket_two(fd, buffer1, start1, len1, buffer2, start2, len2); #else struct msghdr m; struct cmsghdr *cm; struct iovec iov[2]; int bytes_written; _dbus_assert (len1 >= 0); _dbus_assert (len2 >= 0); _dbus_assert (n_fds >= 0); _DBUS_ZERO(iov); iov[0].iov_base = (char*) _dbus_string_get_const_data_len (buffer1, start1, len1); iov[0].iov_len = len1; if (buffer2) { iov[1].iov_base = (char*) _dbus_string_get_const_data_len (buffer2, start2, len2); iov[1].iov_len = len2; } _DBUS_ZERO(m); m.msg_iov = iov; m.msg_iovlen = buffer2 ? 2 : 1; if (n_fds > 0) { m.msg_controllen = CMSG_SPACE(n_fds * sizeof(int)); m.msg_control = alloca(m.msg_controllen); memset(m.msg_control, 0, m.msg_controllen); cm = CMSG_FIRSTHDR(&m); cm->cmsg_level = SOL_SOCKET; cm->cmsg_type = SCM_RIGHTS; cm->cmsg_len = CMSG_LEN(n_fds * sizeof(int)); memcpy(CMSG_DATA(cm), fds, n_fds * sizeof(int)); } again: bytes_written = sendmsg (fd.fd, &m, 0 #if HAVE_DECL_MSG_NOSIGNAL |MSG_NOSIGNAL #endif ); if (bytes_written < 0 && errno == EINTR) goto again; #if 0 if (bytes_written > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_written); #endif return bytes_written; #endif } /** * Like _dbus_write_two() but only works on sockets and is thus * available on Windows. * * @param fd the file descriptor * @param buffer1 first buffer * @param start1 first byte to write in first buffer * @param len1 number of bytes to write from first buffer * @param buffer2 second buffer, or #NULL * @param start2 first byte to write in second buffer * @param len2 number of bytes to write in second buffer * @returns total bytes written from both buffers, or -1 on error */ int _dbus_write_socket_two (DBusSocket fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2) { #if HAVE_DECL_MSG_NOSIGNAL struct iovec vectors[2]; const char *data1; const char *data2; int bytes_written; struct msghdr m; _dbus_assert (buffer1 != NULL); _dbus_assert (start1 >= 0); _dbus_assert (start2 >= 0); _dbus_assert (len1 >= 0); _dbus_assert (len2 >= 0); data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); if (buffer2 != NULL) data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); else { data2 = NULL; start2 = 0; len2 = 0; } vectors[0].iov_base = (char*) data1; vectors[0].iov_len = len1; vectors[1].iov_base = (char*) data2; vectors[1].iov_len = len2; _DBUS_ZERO(m); m.msg_iov = vectors; m.msg_iovlen = data2 ? 2 : 1; again: bytes_written = sendmsg (fd.fd, &m, MSG_NOSIGNAL); if (bytes_written < 0 && errno == EINTR) goto again; return bytes_written; #else return _dbus_write_two (fd.fd, buffer1, start1, len1, buffer2, start2, len2); #endif } /** * Thin wrapper around the read() system call that appends * the data it reads to the DBusString buffer. It appends * up to the given count, and returns the same value * and same errno as read(). The only exception is that * _dbus_read() handles EINTR for you. Also, _dbus_read() can * return ENOMEM, even though regular UNIX read doesn't. * * Unlike _dbus_read_socket(), _dbus_read() is not available * on Windows. * * @param fd the file descriptor to read from * @param buffer the buffer to append data to * @param count the amount of data to read * @returns the number of bytes read or -1 */ int _dbus_read (int fd, DBusString *buffer, int count) { int bytes_read; int start; char *data; _dbus_assert (count >= 0); start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) { errno = ENOMEM; return -1; } data = _dbus_string_get_data_len (buffer, start, count); again: bytes_read = read (fd, data, count); if (bytes_read < 0) { if (errno == EINTR) goto again; else { /* put length back (note that this doesn't actually realloc anything) */ _dbus_string_set_length (buffer, start); return -1; } } else { /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); #if 0 if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif return bytes_read; } } /** * Thin wrapper around the write() system call that writes a part of a * DBusString and handles EINTR for you. * * @param fd the file descriptor to write * @param buffer the buffer to write data from * @param start the first byte in the buffer to write * @param len the number of bytes to try to write * @returns the number of bytes written or -1 on error */ int _dbus_write (int fd, const DBusString *buffer, int start, int len) { const char *data; int bytes_written; data = _dbus_string_get_const_data_len (buffer, start, len); again: bytes_written = write (fd, data, len); if (bytes_written < 0 && errno == EINTR) goto again; #if 0 if (bytes_written > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_written); #endif return bytes_written; } /** * Like _dbus_write() but will use writev() if possible * to write both buffers in sequence. The return value * is the number of bytes written in the first buffer, * plus the number written in the second. If the first * buffer is written successfully and an error occurs * writing the second, the number of bytes in the first * is returned (i.e. the error is ignored), on systems that * don't have writev. Handles EINTR for you. * The second buffer may be #NULL. * * @param fd the file descriptor * @param buffer1 first buffer * @param start1 first byte to write in first buffer * @param len1 number of bytes to write from first buffer * @param buffer2 second buffer, or #NULL * @param start2 first byte to write in second buffer * @param len2 number of bytes to write in second buffer * @returns total bytes written from both buffers, or -1 on error */ int _dbus_write_two (int fd, const DBusString *buffer1, int start1, int len1, const DBusString *buffer2, int start2, int len2) { _dbus_assert (buffer1 != NULL); _dbus_assert (start1 >= 0); _dbus_assert (start2 >= 0); _dbus_assert (len1 >= 0); _dbus_assert (len2 >= 0); #ifdef HAVE_WRITEV { struct iovec vectors[2]; const char *data1; const char *data2; int bytes_written; data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); if (buffer2 != NULL) data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); else { data2 = NULL; start2 = 0; len2 = 0; } vectors[0].iov_base = (char*) data1; vectors[0].iov_len = len1; vectors[1].iov_base = (char*) data2; vectors[1].iov_len = len2; again: bytes_written = writev (fd, vectors, data2 ? 2 : 1); if (bytes_written < 0 && errno == EINTR) goto again; return bytes_written; } #else /* HAVE_WRITEV */ { int ret1, ret2; ret1 = _dbus_write (fd, buffer1, start1, len1); if (ret1 == len1 && buffer2 != NULL) { ret2 = _dbus_write (fd, buffer2, start2, len2); if (ret2 < 0) ret2 = 0; /* we can't report an error as the first write was OK */ return ret1 + ret2; } else return ret1; } #endif /* !HAVE_WRITEV */ } #define _DBUS_MAX_SUN_PATH_LENGTH 99 /** * @def _DBUS_MAX_SUN_PATH_LENGTH * * Maximum length of the path to a UNIX domain socket, * sockaddr_un::sun_path member. POSIX requires that all systems * support at least 100 bytes here, including the nul termination. * We use 99 for the max value to allow for the nul. * * We could probably also do sizeof (addr.sun_path) * but this way we are the same on all platforms * which is probably a good idea. */ /** * Creates a socket and connects it to the UNIX domain socket at the * given path. The connection fd is returned, and is set up as * nonblocking. * * Uses abstract sockets instead of filesystem-linked sockets if * requested (it's possible only on Linux; see "man 7 unix" on Linux). * On non-Linux abstract socket usage always fails. * * This will set FD_CLOEXEC for the socket returned. * * @param path the path to UNIX domain socket * @param abstract #TRUE to use abstract namespace * @param error return location for error code * @returns connection file descriptor or -1 on error */ int _dbus_connect_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error) { int fd; size_t path_len; struct sockaddr_un addr; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("connecting to unix socket %s abstract=%d\n", path, abstract); if (!_dbus_open_unix_socket (&fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); return -1; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; path_len = strlen (path); if (abstract) { #ifdef HAVE_ABSTRACT_SOCKETS addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ path_len++; /* Account for the extra nul byte added to the start of sun_path */ if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Abstract socket name too long\n"); _dbus_close (fd, NULL); return -1; } strncpy (&addr.sun_path[1], path, path_len); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Operating system does not support abstract socket namespace\n"); _dbus_close (fd, NULL); return -1; #endif /* ! HAVE_ABSTRACT_SOCKETS */ } else { if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Socket name too long\n"); _dbus_close (fd, NULL); return -1; } strncpy (addr.sun_path, path, path_len); } if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to connect to socket %s: %s", path, _dbus_strerror (errno)); _dbus_close (fd, NULL); return -1; } if (!_dbus_set_fd_nonblocking (fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_close (fd, NULL); return -1; } return fd; } /** * Creates a UNIX domain socket and connects it to the specified * process to execute. * * This will set FD_CLOEXEC for the socket returned. * * @param path the path to the executable * @param argv the argument list for the process to execute. * argv[0] typically is identical to the path of the executable * @param error return location for error code * @returns connection file descriptor or -1 on error */ int _dbus_connect_exec (const char *path, char *const argv[], DBusError *error) { int fds[2]; pid_t pid; int retval; dbus_bool_t cloexec_done = 0; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("connecting to process %s\n", path); #ifdef SOCK_CLOEXEC retval = socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds); cloexec_done = (retval >= 0); if (retval < 0 && (errno == EINVAL || errno == EPROTOTYPE)) #endif { retval = socketpair (AF_UNIX, SOCK_STREAM, 0, fds); } if (retval < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to create socket pair: %s", _dbus_strerror (errno)); return -1; } if (!cloexec_done) { _dbus_fd_set_close_on_exec (fds[0]); _dbus_fd_set_close_on_exec (fds[1]); } pid = fork (); if (pid < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to fork() to call %s: %s", path, _dbus_strerror (errno)); close (fds[0]); close (fds[1]); return -1; } if (pid == 0) { /* child */ close (fds[0]); dup2 (fds[1], STDIN_FILENO); dup2 (fds[1], STDOUT_FILENO); if (fds[1] != STDIN_FILENO && fds[1] != STDOUT_FILENO) close (fds[1]); /* Inherit STDERR and the controlling terminal from the parent */ _dbus_close_all (); execvp (path, argv); fprintf (stderr, "Failed to execute process %s: %s\n", path, _dbus_strerror (errno)); _exit(1); } /* parent */ close (fds[1]); if (!_dbus_set_fd_nonblocking (fds[0], error)) { _DBUS_ASSERT_ERROR_IS_SET (error); close (fds[0]); return -1; } return fds[0]; } /** * Creates a socket and binds it to the given path, * then listens on the socket. The socket is * set to be nonblocking. * * Uses abstract sockets instead of filesystem-linked * sockets if requested (it's possible only on Linux; * see "man 7 unix" on Linux). * On non-Linux abstract socket usage always fails. * * This will set FD_CLOEXEC for the socket returned * * @param path the socket name * @param abstract #TRUE to use abstract namespace * @param error return location for errors * @returns the listening file descriptor or -1 on error */ int _dbus_listen_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error) { int listen_fd; struct sockaddr_un addr; size_t path_len; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("listening on unix socket %s abstract=%d\n", path, abstract); if (!_dbus_open_unix_socket (&listen_fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); return -1; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; path_len = strlen (path); if (abstract) { #ifdef HAVE_ABSTRACT_SOCKETS /* remember that abstract names aren't nul-terminated so we rely * on sun_path being filled in with zeroes above. */ addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ path_len++; /* Account for the extra nul byte added to the start of sun_path */ if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Abstract socket name too long\n"); _dbus_close (listen_fd, NULL); return -1; } strncpy (&addr.sun_path[1], path, path_len); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Operating system does not support abstract socket namespace\n"); _dbus_close (listen_fd, NULL); return -1; #endif /* ! HAVE_ABSTRACT_SOCKETS */ } else { /* Discussed security implications of this with Nalin, * and we couldn't think of where it would kick our ass, but * it still seems a bit sucky. It also has non-security suckage; * really we'd prefer to exit if the socket is already in use. * But there doesn't seem to be a good way to do this. * * Just to be extra careful, I threw in the stat() - clearly * the stat() can't *fix* any security issue, but it at least * avoids inadvertent/accidental data loss. */ { struct stat sb; if (stat (path, &sb) == 0 && S_ISSOCK (sb.st_mode)) unlink (path); } if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Socket name too long\n"); _dbus_close (listen_fd, NULL); return -1; } strncpy (addr.sun_path, path, path_len); } if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to bind socket \"%s\": %s", path, _dbus_strerror (errno)); _dbus_close (listen_fd, NULL); return -1; } if (listen (listen_fd, 30 /* backlog */) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to listen on socket \"%s\": %s", path, _dbus_strerror (errno)); _dbus_close (listen_fd, NULL); return -1; } if (!_dbus_set_fd_nonblocking (listen_fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_close (listen_fd, NULL); return -1; } /* Try opening up the permissions, but if we can't, just go ahead * and continue, maybe it will be good enough. */ if (!abstract && chmod (path, 0777) < 0) _dbus_warn ("Could not set mode 0777 on socket %s\n", path); return listen_fd; } /** * Acquires one or more sockets passed in from systemd. The sockets * are set to be nonblocking. * * This will set FD_CLOEXEC for the sockets returned. * * @param fds the file descriptors * @param error return location for errors * @returns the number of file descriptors */ int _dbus_listen_systemd_sockets (DBusSocket **fds, DBusError *error) { #ifdef HAVE_SYSTEMD int r, n; int fd; DBusSocket *new_fds; _DBUS_ASSERT_ERROR_IS_CLEAR (error); n = sd_listen_fds (TRUE); if (n < 0) { dbus_set_error (error, _dbus_error_from_errno (-n), "Failed to acquire systemd socket: %s", _dbus_strerror (-n)); return -1; } if (n <= 0) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "No socket received."); return -1; } for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { r = sd_is_socket (fd, AF_UNSPEC, SOCK_STREAM, 1); if (r < 0) { dbus_set_error (error, _dbus_error_from_errno (-r), "Failed to verify systemd socket type: %s", _dbus_strerror (-r)); return -1; } if (!r) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Passed socket has wrong type."); return -1; } } /* OK, the file descriptors are all good, so let's take posession of them then. */ new_fds = dbus_new (DBusSocket, n); if (!new_fds) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Failed to allocate file handle array."); goto fail; } for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { if (!_dbus_set_fd_nonblocking (fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto fail; } new_fds[fd - SD_LISTEN_FDS_START].fd = fd; } *fds = new_fds; return n; fail: for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { _dbus_close (fd, NULL); } dbus_free (new_fds); return -1; #else dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "dbus was compiled without systemd support"); return -1; #endif } /** * Creates a socket and connects to a socket at the given host * and port. The connection fd is returned, and is set up as * nonblocking. * * This will set FD_CLOEXEC for the socket returned * * @param host the host name to connect to * @param port the port to connect to * @param family the address family to listen on, NULL for all * @param error return location for error code * @returns connection file descriptor or -1 on error */ DBusSocket _dbus_connect_tcp_socket (const char *host, const char *port, const char *family, DBusError *error) { return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error); } DBusSocket _dbus_connect_tcp_socket_with_nonce (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error) { int saved_errno = 0; DBusSocket fd = DBUS_SOCKET_INIT; int res; struct addrinfo hints; struct addrinfo *ai, *tmp; _DBUS_ASSERT_ERROR_IS_CLEAR(error); _DBUS_ZERO (hints); if (!family) hints.ai_family = AF_UNSPEC; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) hints.ai_family = AF_INET6; else { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Unknown address family %s", family); return _dbus_socket_get_invalid (); } hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; if ((res = getaddrinfo(host, port, &hints, &ai)) != 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host, port, gai_strerror(res), res); return _dbus_socket_get_invalid (); } tmp = ai; while (tmp) { if (!_dbus_open_socket (&fd.fd, tmp->ai_family, SOCK_STREAM, 0, error)) { freeaddrinfo(ai); _DBUS_ASSERT_ERROR_IS_SET(error); return _dbus_socket_get_invalid (); } _DBUS_ASSERT_ERROR_IS_CLEAR(error); if (connect (fd.fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) { saved_errno = errno; _dbus_close (fd.fd, NULL); fd.fd = -1; tmp = tmp->ai_next; continue; } break; } freeaddrinfo(ai); if (fd.fd == -1) { dbus_set_error (error, _dbus_error_from_errno (saved_errno), "Failed to connect to socket \"%s:%s\" %s", host, port, _dbus_strerror(saved_errno)); return _dbus_socket_get_invalid (); } if (noncefile != NULL) { DBusString noncefileStr; dbus_bool_t ret; _dbus_string_init_const (&noncefileStr, noncefile); ret = _dbus_send_nonce (fd, &noncefileStr, error); _dbus_string_free (&noncefileStr); if (!ret) { _dbus_close (fd.fd, NULL); return _dbus_socket_get_invalid (); } } if (!_dbus_set_fd_nonblocking (fd.fd, error)) { _dbus_close (fd.fd, NULL); return _dbus_socket_get_invalid (); } return fd; } /** * Creates a socket and binds it to the given path, then listens on * the socket. The socket is set to be nonblocking. In case of port=0 * a random free port is used and returned in the port parameter. * If inaddr_any is specified, the hostname is ignored. * * This will set FD_CLOEXEC for the socket returned * * @param host the host name to listen on * @param port the port to listen on, if zero a free port will be used * @param family the address family to listen on, NULL for all * @param retport string to return the actual port listened on * @param fds_p location to store returned file descriptors * @param error return location for errors * @returns the number of listening file descriptors or -1 on error */ int _dbus_listen_tcp_socket (const char *host, const char *port, const char *family, DBusString *retport, DBusSocket **fds_p, DBusError *error) { int saved_errno; int nlisten_fd = 0, res, i; DBusSocket *listen_fd = NULL; struct addrinfo hints; struct addrinfo *ai, *tmp; unsigned int reuseaddr; *fds_p = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _DBUS_ZERO (hints); if (!family) hints.ai_family = AF_UNSPEC; else if (!strcmp(family, "ipv4")) hints.ai_family = AF_INET; else if (!strcmp(family, "ipv6")) hints.ai_family = AF_INET6; else { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Unknown address family %s", family); return -1; } hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; redo_lookup_with_port: ai = NULL; if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host ? host : "*", port, gai_strerror(res), res); goto failed; } tmp = ai; while (tmp) { int fd = -1, tcp_nodelay_on; DBusSocket *newlisten_fd; if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); goto failed; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); reuseaddr = 1; if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1) { _dbus_warn ("Failed to set socket option \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (errno)); } /* Nagle's algorithm imposes a huge delay on the initial messages going over TCP. */ tcp_nodelay_on = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay_on, sizeof (tcp_nodelay_on)) == -1) { _dbus_warn ("Failed to set TCP_NODELAY socket option \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (errno)); } if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) { saved_errno = errno; _dbus_close(fd, NULL); if (saved_errno == EADDRINUSE) { /* Depending on kernel policy, binding to an IPv6 address might implicitly bind to a corresponding IPv4 address or vice versa, resulting in EADDRINUSE for the other one (e.g. bindv6only=0 on Linux). Also, after we "goto redo_lookup_with_port" after binding a port on one of the possible addresses, we will try to bind that same port on every address, including the same address again for a second time; that one will also fail with EADDRINUSE. For both those reasons, ignore EADDRINUSE here */ tmp = tmp->ai_next; continue; } dbus_set_error (error, _dbus_error_from_errno (saved_errno), "Failed to bind socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (saved_errno)); goto failed; } if (listen (fd, 30 /* backlog */) < 0) { saved_errno = errno; _dbus_close (fd, NULL); dbus_set_error (error, _dbus_error_from_errno (saved_errno), "Failed to listen on socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (saved_errno)); goto failed; } newlisten_fd = dbus_realloc(listen_fd, sizeof(DBusSocket)*(nlisten_fd+1)); if (!newlisten_fd) { saved_errno = errno; _dbus_close (fd, NULL); dbus_set_error (error, _dbus_error_from_errno (saved_errno), "Failed to allocate file handle array: %s", _dbus_strerror (saved_errno)); goto failed; } listen_fd = newlisten_fd; listen_fd[nlisten_fd].fd = fd; nlisten_fd++; if (!_dbus_string_get_length(retport)) { /* If the user didn't specify a port, or used 0, then the kernel chooses a port. After the first address is bound to, we need to force all remaining addresses to use the same port */ if (!port || !strcmp(port, "0")) { int result; struct sockaddr_storage addr; socklen_t addrlen; char portbuf[50]; addrlen = sizeof(addr); result = getsockname(fd, (struct sockaddr*) &addr, &addrlen); if (result == -1 || (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0, portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to resolve port \"%s:%s\": %s (%s)", host ? host : "*", port, gai_strerror(res), res); goto failed; } if (!_dbus_string_append(retport, portbuf)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } /* Release current address list & redo lookup */ port = _dbus_string_get_const_data(retport); freeaddrinfo(ai); goto redo_lookup_with_port; } else { if (!_dbus_string_append(retport, port)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } } } tmp = tmp->ai_next; } freeaddrinfo(ai); ai = NULL; if (!nlisten_fd) { errno = EADDRINUSE; dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to bind socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (errno)); goto failed; } for (i = 0 ; i < nlisten_fd ; i++) { if (!_dbus_set_fd_nonblocking (listen_fd[i].fd, error)) { goto failed; } } *fds_p = listen_fd; return nlisten_fd; failed: if (ai) freeaddrinfo(ai); for (i = 0 ; i < nlisten_fd ; i++) _dbus_close(listen_fd[i].fd, NULL); dbus_free(listen_fd); return -1; } static dbus_bool_t write_credentials_byte (int server_fd, DBusError *error) { int bytes_written; char buf[1] = { '\0' }; #if defined(HAVE_CMSGCRED) union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; } cmsg; struct iovec iov; struct msghdr msg; iov.iov_base = buf; iov.iov_len = 1; _DBUS_ZERO(msg); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred)); _DBUS_ZERO(cmsg); cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred)); cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_CREDS; #endif _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: #if defined(HAVE_CMSGCRED) bytes_written = sendmsg (server_fd, &msg, 0 #if HAVE_DECL_MSG_NOSIGNAL |MSG_NOSIGNAL #endif ); /* If we HAVE_CMSGCRED, the OS still might not let us sendmsg() * with a SOL_SOCKET/SCM_CREDS message - for instance, FreeBSD * only allows that on AF_UNIX. Try just doing a send() instead. */ if (bytes_written < 0 && errno == EINVAL) #endif { bytes_written = send (server_fd, buf, 1, 0 #if HAVE_DECL_MSG_NOSIGNAL |MSG_NOSIGNAL #endif ); } if (bytes_written < 0 && errno == EINTR) goto again; if (bytes_written < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to write credentials byte: %s", _dbus_strerror (errno)); return FALSE; } else if (bytes_written == 0) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "wrote zero bytes writing credentials byte"); return FALSE; } else { _dbus_assert (bytes_written == 1); _dbus_verbose ("wrote credentials byte\n"); return TRUE; } } /* return FALSE on OOM, TRUE otherwise, even if no credentials were found */ static dbus_bool_t add_linux_security_label_to_credentials (int client_fd, DBusCredentials *credentials) { #if defined(__linux__) && defined(SO_PEERSEC) DBusString buf; socklen_t len = 1024; dbus_bool_t oom = FALSE; if (!_dbus_string_init_preallocated (&buf, len) || !_dbus_string_set_length (&buf, len)) return FALSE; while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC, _dbus_string_get_data (&buf), &len) < 0) { int e = errno; _dbus_verbose ("getsockopt failed with %s, len now %lu\n", _dbus_strerror (e), (unsigned long) len); if (e != ERANGE || len <= _dbus_string_get_length_uint (&buf)) { _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n", _dbus_strerror (e)); goto out; } /* If not enough space, len is updated to be enough. * Try again with a large enough buffer. */ if (!_dbus_string_set_length (&buf, len)) { oom = TRUE; goto out; } _dbus_verbose ("will try again with %lu\n", (unsigned long) len); } if (len <= 0) { _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n", (unsigned long) len); goto out; } if (len > _dbus_string_get_length_uint (&buf)) { _dbus_verbose ("%lu > %u", (unsigned long) len, _dbus_string_get_length_uint (&buf)); _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed"); } if (_dbus_string_get_byte (&buf, len - 1) == 0) { /* the kernel included the trailing \0 in its count, * but DBusString always has an extra \0 after the data anyway */ _dbus_verbose ("subtracting trailing \\0\n"); len--; } if (!_dbus_string_set_length (&buf, len)) { _dbus_assert_not_reached ("shortening string should not lead to OOM"); oom = TRUE; goto out; } if (strlen (_dbus_string_get_const_data (&buf)) != len) { /* LSM people on the linux-security-module@ mailing list say this * should never happen: the label should be a bytestring with * an optional trailing \0 */ _dbus_verbose ("security label from kernel had an embedded \\0, " "ignoring it\n"); goto out; } _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n", (unsigned long) len, _dbus_string_get_const_data (&buf)); if (!_dbus_credentials_add_linux_security_label (credentials, _dbus_string_get_const_data (&buf))) { oom = TRUE; goto out; } out: _dbus_string_free (&buf); return !oom; #else /* no error */ return TRUE; #endif } /** * Reads a single byte which must be nul (an error occurs otherwise), * and reads unix credentials if available. Clears the credentials * object, then adds pid/uid if available, so any previous credentials * stored in the object are lost. * * DBusServer makes the security assumption that the credentials * returned by this method are the credentials that were active * at the time the socket was opened. Do not add APIs to this * method that would break that assumption. * * In particular, it is incorrect to use any API of the form * "get the process ID at the other end of the connection, then * determine its uid, gid, or other credentials from the pid" * (e.g. looking in /proc on Linux). If we did that, we would * be vulnerable to several attacks. A malicious process could * queue up the rest of the authentication handshake and a malicious * message that it should not be allowed to send, then race with * the DBusServer to exec() a more privileged (e.g. setuid) binary that * would have been allowed to send that message; or it could exit, * and arrange for enough setuid processes to be started that its * pid would be recycled for one of those processes with high * probability; or it could fd-pass the connection to a more * privileged process. * * Return value indicates whether a byte was read, not whether * we got valid credentials. On some systems, such as Linux, * reading/writing the byte isn't actually required, but we do it * anyway just to avoid multiple codepaths. * * Fails if no byte is available, so you must select() first. * * The point of the byte is that on some systems we have to * use sendmsg()/recvmsg() to transmit credentials. * * @param client_fd the client file descriptor * @param credentials object to add client credentials to * @param error location to store error code * @returns #TRUE on success */ dbus_bool_t _dbus_read_credentials_socket (DBusSocket client_fd, DBusCredentials *credentials, DBusError *error) { struct msghdr msg; struct iovec iov; char buf; dbus_uid_t uid_read; dbus_pid_t pid_read; int bytes_read; #ifdef HAVE_CMSGCRED union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; } cmsg; #endif /* The POSIX spec certainly doesn't promise this, but * we need these assertions to fail as soon as we're wrong about * it so we can do the porting fixups */ _DBUS_STATIC_ASSERT (sizeof (pid_t) <= sizeof (dbus_pid_t)); _DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (dbus_uid_t)); _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t)); uid_read = DBUS_UID_UNSET; pid_read = DBUS_PID_UNSET; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_credentials_clear (credentials); iov.iov_base = &buf; iov.iov_len = 1; _DBUS_ZERO(msg); msg.msg_iov = &iov; msg.msg_iovlen = 1; #if defined(HAVE_CMSGCRED) _DBUS_ZERO(cmsg); msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred)); #endif again: bytes_read = recvmsg (client_fd.fd, &msg, 0); if (bytes_read < 0) { if (errno == EINTR) goto again; /* EAGAIN or EWOULDBLOCK would be unexpected here since we would * normally only call read_credentials if the socket was ready * for reading */ dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to read credentials byte: %s", _dbus_strerror (errno)); return FALSE; } else if (bytes_read == 0) { /* this should not happen unless we are using recvmsg wrong, * so is essentially here for paranoia */ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to read credentials byte (zero-length read)"); return FALSE; } else if (buf != '\0') { dbus_set_error (error, DBUS_ERROR_FAILED, "Credentials byte was not nul"); return FALSE; } _dbus_verbose ("read credentials byte\n"); { #ifdef SO_PEERCRED /* Supported by at least Linux and OpenBSD, with minor differences. * * This mechanism passes the process ID through and does not require * the peer's cooperation, so we prefer it over all others. Notably, * Linux also supports SCM_CREDENTIALS, which is similar to FreeBSD * SCM_CREDS; it's implemented in GIO, but we don't use it in dbus at all, * because this is much less fragile. */ #ifdef __OpenBSD__ struct sockpeercred cr; #else struct ucred cr; #endif int cr_len = sizeof (cr); if (getsockopt (client_fd.fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) != 0) { _dbus_verbose ("Failed to getsockopt(SO_PEERCRED): %s\n", _dbus_strerror (errno)); } else if (cr_len != sizeof (cr)) { _dbus_verbose ("Failed to getsockopt(SO_PEERCRED), returned %d bytes, expected %d\n", cr_len, (int) sizeof (cr)); } else { pid_read = cr.pid; uid_read = cr.uid; } #elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID) /* Another variant of the above - used on NetBSD */ struct unpcbid cr; socklen_t cr_len = sizeof (cr); if (getsockopt (client_fd.fd, 0, LOCAL_PEEREID, &cr, &cr_len) != 0) { _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID): %s\n", _dbus_strerror (errno)); } else if (cr_len != sizeof (cr)) { _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID), returned %d bytes, expected %d\n", cr_len, (int) sizeof (cr)); } else { pid_read = cr.unp_pid; uid_read = cr.unp_euid; } #elif defined(HAVE_CMSGCRED) /* We only check for HAVE_CMSGCRED, but we're really assuming that the * presence of that struct implies SCM_CREDS. Supported by at least * FreeBSD and DragonflyBSD. * * This mechanism requires the peer to help us (it has to send us a * SCM_CREDS message) but it does pass the process ID through, * which makes it better than getpeereid(). */ struct cmsgcred *cred; struct cmsghdr *cmsgp; for (cmsgp = CMSG_FIRSTHDR (&msg); cmsgp != NULL; cmsgp = CMSG_NXTHDR (&msg, cmsgp)) { if (cmsgp->cmsg_type == SCM_CREDS && cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_len >= CMSG_LEN (sizeof (struct cmsgcred))) { cred = (struct cmsgcred *) CMSG_DATA (cmsgp); pid_read = cred->cmcred_pid; uid_read = cred->cmcred_euid; break; } } #elif defined(HAVE_GETPEERUCRED) /* Supported in at least Solaris >= 10. It should probably be higher * up this list, because it carries the pid and we use this code path * for audit data. */ ucred_t * ucred = NULL; if (getpeerucred (client_fd.fd, &ucred) == 0) { pid_read = ucred_getpid (ucred); uid_read = ucred_geteuid (ucred); #ifdef HAVE_ADT /* generate audit session data based on socket ucred */ adt_session_data_t *adth = NULL; adt_export_data_t *data = NULL; size_t size = 0; if (adt_start_session (&adth, NULL, 0) || (adth == NULL)) { _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno)); } else { if (adt_set_from_ucred (adth, ucred, ADT_NEW)) { _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno)); } else { size = adt_export_session_data (adth, &data); if (size <= 0) { _dbus_verbose ("Failed to adt_export_session_data(): %s\n", _dbus_strerror (errno)); } else { _dbus_credentials_add_adt_audit_data (credentials, data, size); free (data); } } (void) adt_end_session (adth); } #endif /* HAVE_ADT */ } else { _dbus_verbose ("Failed to getpeerucred() credentials: %s\n", _dbus_strerror (errno)); } if (ucred != NULL) ucred_free (ucred); /* ---------------------------------------------------------------- * When adding new mechanisms, please add them above this point * if they support passing the process ID through, or below if not. * ---------------------------------------------------------------- */ #elif defined(HAVE_GETPEEREID) /* getpeereid() originates from D.J. Bernstein and is fairly * widely-supported. According to a web search, it might be present in * any/all of: * * - AIX? * - Blackberry? * - Cygwin * - FreeBSD 4.6+ (but we prefer SCM_CREDS: it carries the pid) * - Mac OS X * - Minix 3.1.8+ * - MirBSD? * - NetBSD 5.0+ (but LOCAL_PEEREID would be better: it carries the pid) * - OpenBSD 3.0+ (but we prefer SO_PEERCRED: it carries the pid) * - QNX? */ uid_t euid; gid_t egid; if (getpeereid (client_fd.fd, &euid, &egid) == 0) { uid_read = euid; } else { _dbus_verbose ("Failed to getpeereid() credentials: %s\n", _dbus_strerror (errno)); } #else /* no supported mechanism */ #warning Socket credentials not supported on this Unix OS #warning Please tell https://bugs.freedesktop.org/enter_bug.cgi?product=DBus /* Please add other operating systems known to support at least one of * the mechanisms above to this list, keeping alphabetical order. * Everything not in this list is best-effort. */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__linux__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # error Credentials passing not working on this OS is a regression! #endif _dbus_verbose ("Socket credentials not supported on this OS\n"); #endif } _dbus_verbose ("Credentials:" " pid "DBUS_PID_FORMAT " uid "DBUS_UID_FORMAT "\n", pid_read, uid_read); if (pid_read != DBUS_PID_UNSET) { if (!_dbus_credentials_add_pid (credentials, pid_read)) { _DBUS_SET_OOM (error); return FALSE; } } if (uid_read != DBUS_UID_UNSET) { if (!_dbus_credentials_add_unix_uid (credentials, uid_read)) { _DBUS_SET_OOM (error); return FALSE; } } if (!add_linux_security_label_to_credentials (client_fd.fd, credentials)) { _DBUS_SET_OOM (error); return FALSE; } return TRUE; } /** * Sends a single nul byte with our UNIX credentials as ancillary * data. Returns #TRUE if the data was successfully written. On * systems that don't support sending credentials, just writes a byte, * doesn't send any credentials. On some systems, such as Linux, * reading/writing the byte isn't actually required, but we do it * anyway just to avoid multiple codepaths. * * Fails if no byte can be written, so you must select() first. * * The point of the byte is that on some systems we have to * use sendmsg()/recvmsg() to transmit credentials. * * @param server_fd file descriptor for connection to server * @param error return location for error code * @returns #TRUE if the byte was sent */ dbus_bool_t _dbus_send_credentials_socket (DBusSocket server_fd, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (write_credentials_byte (server_fd.fd, error)) return TRUE; else return FALSE; } /** * Accepts a connection on a listening socket. * Handles EINTR for you. * * This will enable FD_CLOEXEC for the returned socket. * * @param listen_fd the listen file descriptor * @returns the connection fd of the client, or -1 on error */ DBusSocket _dbus_accept (DBusSocket listen_fd) { DBusSocket client_fd; struct sockaddr addr; socklen_t addrlen; #ifdef HAVE_ACCEPT4 dbus_bool_t cloexec_done; #endif addrlen = sizeof (addr); retry: #ifdef HAVE_ACCEPT4 /* * At compile-time, we assume that if accept4() is available in * libc headers, SOCK_CLOEXEC is too. At runtime, it is still * not necessarily true that either is supported by the running kernel. */ client_fd.fd = accept4 (listen_fd.fd, &addr, &addrlen, SOCK_CLOEXEC); cloexec_done = client_fd.fd >= 0; if (client_fd.fd < 0 && (errno == ENOSYS || errno == EINVAL)) #endif { client_fd.fd = accept (listen_fd.fd, &addr, &addrlen); } if (client_fd.fd < 0) { if (errno == EINTR) goto retry; } _dbus_verbose ("client fd %d accepted\n", client_fd.fd); #ifdef HAVE_ACCEPT4 if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec(client_fd.fd); } return client_fd; } /** * Checks to make sure the given directory is * private to the user * * @param dir the name of the directory * @param error error return * @returns #FALSE on failure **/ dbus_bool_t _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) { const char *directory; struct stat sb; _DBUS_ASSERT_ERROR_IS_CLEAR (error); directory = _dbus_string_get_const_data (dir); if (stat (directory, &sb) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "%s", _dbus_strerror (errno)); return FALSE; } if (sb.st_uid != geteuid ()) { dbus_set_error (error, DBUS_ERROR_FAILED, "%s directory is owned by user %lu, not %lu", directory, (unsigned long) sb.st_uid, (unsigned long) geteuid ()); return FALSE; } if ((S_IROTH & sb.st_mode) || (S_IWOTH & sb.st_mode) || (S_IRGRP & sb.st_mode) || (S_IWGRP & sb.st_mode)) { dbus_set_error (error, DBUS_ERROR_FAILED, "%s directory is not private to the user", directory); return FALSE; } return TRUE; } static dbus_bool_t fill_user_info_from_passwd (struct passwd *p, DBusUserInfo *info, DBusError *error) { _dbus_assert (p->pw_name != NULL); _dbus_assert (p->pw_dir != NULL); info->uid = p->pw_uid; info->primary_gid = p->pw_gid; info->username = _dbus_strdup (p->pw_name); info->homedir = _dbus_strdup (p->pw_dir); if (info->username == NULL || info->homedir == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } return TRUE; } static dbus_bool_t fill_user_info (DBusUserInfo *info, dbus_uid_t uid, const DBusString *username, DBusError *error) { const char *username_c; /* exactly one of username/uid provided */ _dbus_assert (username != NULL || uid != DBUS_UID_UNSET); _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); info->uid = DBUS_UID_UNSET; info->primary_gid = DBUS_GID_UNSET; info->group_ids = NULL; info->n_group_ids = 0; info->username = NULL; info->homedir = NULL; if (username != NULL) username_c = _dbus_string_get_const_data (username); else username_c = NULL; /* For now assuming that the getpwnam() and getpwuid() flavors * are always symmetrical, if not we have to add more configure * checks */ #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) { struct passwd *p; int result; size_t buflen; char *buf; struct passwd p_str; /* retrieve maximum needed size for buf */ buflen = sysconf (_SC_GETPW_R_SIZE_MAX); /* sysconf actually returns a long, but everything else expects size_t, * so just recast here. * https://bugs.freedesktop.org/show_bug.cgi?id=17061 */ if ((long) buflen <= 0) buflen = 1024; result = -1; while (1) { buf = dbus_malloc (buflen); if (buf == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } p = NULL; #ifdef HAVE_POSIX_GETPWNAM_R if (uid != DBUS_UID_UNSET) result = getpwuid_r (uid, &p_str, buf, buflen, &p); else result = getpwnam_r (username_c, &p_str, buf, buflen, &p); #else if (uid != DBUS_UID_UNSET) p = getpwuid_r (uid, &p_str, buf, buflen); else p = getpwnam_r (username_c, &p_str, buf, buflen); result = 0; #endif /* !HAVE_POSIX_GETPWNAM_R */ //Try a bigger buffer if ERANGE was returned if (result == ERANGE && buflen < 512 * 1024) { dbus_free (buf); buflen *= 2; } else { break; } } if (result == 0 && p == &p_str) { if (!fill_user_info_from_passwd (p, info, error)) { dbus_free (buf); return FALSE; } dbus_free (buf); } else { dbus_set_error (error, _dbus_error_from_errno (errno), "User \"%s\" unknown or no memory to allocate password entry\n", username_c ? username_c : "???"); _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???"); dbus_free (buf); return FALSE; } } #else /* ! HAVE_GETPWNAM_R */ { /* I guess we're screwed on thread safety here */ struct passwd *p; if (uid != DBUS_UID_UNSET) p = getpwuid (uid); else p = getpwnam (username_c); if (p != NULL) { if (!fill_user_info_from_passwd (p, info, error)) { return FALSE; } } else { dbus_set_error (error, _dbus_error_from_errno (errno), "User \"%s\" unknown or no memory to allocate password entry\n", username_c ? username_c : "???"); _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???"); return FALSE; } } #endif /* ! HAVE_GETPWNAM_R */ /* Fill this in so we can use it to get groups */ username_c = info->username; #ifdef HAVE_GETGROUPLIST { gid_t *buf; int buf_count; int i; int initial_buf_count; initial_buf_count = 17; buf_count = initial_buf_count; buf = dbus_new (gid_t, buf_count); if (buf == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0) { gid_t *new; /* Presumed cause of negative return code: buf has insufficient entries to hold the entire group list. The Linux behavior in this case is to pass back the actual number of groups in buf_count, but on Mac OS X 10.5, buf_count is unhelpfully left alone. So as a hack, try to help out a bit by guessing a larger number of groups, within reason.. might still fail, of course, but we can at least print a more informative message. I looked up the "right way" to do this by downloading Apple's own source code for the "id" command, and it turns out that they use an undocumented library function getgrouplist_2 (!) which is not declared in any header in /usr/include (!!). That did not seem like the way to go here. */ if (buf_count == initial_buf_count) { buf_count *= 16; /* Retry with an arbitrarily scaled-up array */ } new = dbus_realloc (buf, buf_count * sizeof (buf[0])); if (new == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_free (buf); goto failed; } buf = new; errno = 0; if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0) { if (errno == 0) { _dbus_warn ("It appears that username \"%s\" is in more than %d groups.\nProceeding with just the first %d groups.", username_c, buf_count, buf_count); } else { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to get groups for username \"%s\" primary GID " DBUS_GID_FORMAT ": %s\n", username_c, info->primary_gid, _dbus_strerror (errno)); dbus_free (buf); goto failed; } } } info->group_ids = dbus_new (dbus_gid_t, buf_count); if (info->group_ids == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_free (buf); goto failed; } for (i = 0; i < buf_count; ++i) info->group_ids[i] = buf[i]; info->n_group_ids = buf_count; dbus_free (buf); } #else /* HAVE_GETGROUPLIST */ { /* We just get the one group ID */ info->group_ids = dbus_new (dbus_gid_t, 1); if (info->group_ids == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } info->n_group_ids = 1; (info->group_ids)[0] = info->primary_gid; } #endif /* HAVE_GETGROUPLIST */ _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; failed: _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } /** * Gets user info for the given username. * * @param info user info object to initialize * @param username the username * @param error error return * @returns #TRUE on success */ dbus_bool_t _dbus_user_info_fill (DBusUserInfo *info, const DBusString *username, DBusError *error) { return fill_user_info (info, DBUS_UID_UNSET, username, error); } /** * Gets user info for the given user ID. * * @param info user info object to initialize * @param uid the user ID * @param error error return * @returns #TRUE on success */ dbus_bool_t _dbus_user_info_fill_uid (DBusUserInfo *info, dbus_uid_t uid, DBusError *error) { return fill_user_info (info, uid, NULL, error); } /** * Adds the credentials of the current process to the * passed-in credentials object. * * @param credentials credentials to add to * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added */ dbus_bool_t _dbus_credentials_add_from_current_process (DBusCredentials *credentials) { /* The POSIX spec certainly doesn't promise this, but * we need these assertions to fail as soon as we're wrong about * it so we can do the porting fixups */ _DBUS_STATIC_ASSERT (sizeof (pid_t) <= sizeof (dbus_pid_t)); _DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (dbus_uid_t)); _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t)); if (!_dbus_credentials_add_pid(credentials, _dbus_getpid())) return FALSE; if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid())) return FALSE; return TRUE; } /** * Append to the string the identity we would like to have when we * authenticate, on UNIX this is the current process UID and on * Windows something else, probably a Windows SID string. No escaping * is required, that is done in dbus-auth.c. The username here * need not be anything human-readable, it can be the machine-readable * form i.e. a user id. * * @param str the string to append to * @returns #FALSE on no memory */ dbus_bool_t _dbus_append_user_from_current_process (DBusString *str) { return _dbus_string_append_uint (str, _dbus_geteuid ()); } /** * Gets our process ID * @returns process ID */ dbus_pid_t _dbus_getpid (void) { return getpid (); } /** Gets our UID * @returns process UID */ dbus_uid_t _dbus_getuid (void) { return getuid (); } /** Gets our effective UID * @returns process effective UID */ dbus_uid_t _dbus_geteuid (void) { return geteuid (); } /** * The only reason this is separate from _dbus_getpid() is to allow it * on Windows for logging but not for other purposes. * * @returns process ID to put in log messages */ unsigned long _dbus_pid_for_log (void) { return getpid (); } /** * Gets a UID from a UID string. * * @param uid_str the UID in string form * @param uid UID to fill in * @returns #TRUE if successfully filled in UID */ dbus_bool_t _dbus_parse_uid (const DBusString *uid_str, dbus_uid_t *uid) { int end; long val; if (_dbus_string_get_length (uid_str) == 0) { _dbus_verbose ("UID string was zero length\n"); return FALSE; } val = -1; end = 0; if (!_dbus_string_parse_int (uid_str, 0, &val, &end)) { _dbus_verbose ("could not parse string as a UID\n"); return FALSE; } if (end != _dbus_string_get_length (uid_str)) { _dbus_verbose ("string contained trailing stuff after UID\n"); return FALSE; } *uid = val; return TRUE; } #if !DBUS_USE_SYNC /* To be thread-safe by default on platforms that don't necessarily have * atomic operations (notably Debian armel, which is armv4t), we must * use a mutex that can be initialized statically, like this. * GLib >= 2.32 uses a similar system. */ static pthread_mutex_t atomic_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /** * Atomically increments an integer * * @param atomic pointer to the integer to increment * @returns the value before incrementing */ dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic) { #if DBUS_USE_SYNC return __sync_add_and_fetch(&atomic->value, 1)-1; #else dbus_int32_t res; pthread_mutex_lock (&atomic_mutex); res = atomic->value; atomic->value += 1; pthread_mutex_unlock (&atomic_mutex); return res; #endif } /** * Atomically decrement an integer * * @param atomic pointer to the integer to decrement * @returns the value before decrementing */ dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic) { #if DBUS_USE_SYNC return __sync_sub_and_fetch(&atomic->value, 1)+1; #else dbus_int32_t res; pthread_mutex_lock (&atomic_mutex); res = atomic->value; atomic->value -= 1; pthread_mutex_unlock (&atomic_mutex); return res; #endif } /** * Atomically get the value of an integer. It may change at any time * thereafter, so this is mostly only useful for assertions. * * @param atomic pointer to the integer to get * @returns the value at this moment */ dbus_int32_t _dbus_atomic_get (DBusAtomic *atomic) { #if DBUS_USE_SYNC __sync_synchronize (); return atomic->value; #else dbus_int32_t res; pthread_mutex_lock (&atomic_mutex); res = atomic->value; pthread_mutex_unlock (&atomic_mutex); return res; #endif } /** * Wrapper for poll(). * * @param fds the file descriptors to poll * @param n_fds number of descriptors in the array * @param timeout_milliseconds timeout or -1 for infinite * @returns numbers of fds with revents, or <0 on error */ int _dbus_poll (DBusPollFD *fds, int n_fds, int timeout_milliseconds) { #if defined(HAVE_POLL) && !defined(BROKEN_POLL) /* DBusPollFD is a struct pollfd in this code path, so we can just poll() */ if (timeout_milliseconds < -1) { timeout_milliseconds = -1; } return poll (fds, n_fds, timeout_milliseconds); #else /* ! HAVE_POLL */ /* Emulate poll() in terms of select() */ fd_set read_set, write_set, err_set; int max_fd = 0; int i; struct timeval tv; int ready; FD_ZERO (&read_set); FD_ZERO (&write_set); FD_ZERO (&err_set); for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; if (fdp->events & _DBUS_POLLIN) FD_SET (fdp->fd, &read_set); if (fdp->events & _DBUS_POLLOUT) FD_SET (fdp->fd, &write_set); FD_SET (fdp->fd, &err_set); max_fd = MAX (max_fd, fdp->fd); } tv.tv_sec = timeout_milliseconds / 1000; tv.tv_usec = (timeout_milliseconds % 1000) * 1000; ready = select (max_fd + 1, &read_set, &write_set, &err_set, timeout_milliseconds < 0 ? NULL : &tv); if (ready > 0) { for (i = 0; i < n_fds; i++) { DBusPollFD *fdp = &fds[i]; fdp->revents = 0; if (FD_ISSET (fdp->fd, &read_set)) fdp->revents |= _DBUS_POLLIN; if (FD_ISSET (fdp->fd, &write_set)) fdp->revents |= _DBUS_POLLOUT; if (FD_ISSET (fdp->fd, &err_set)) fdp->revents |= _DBUS_POLLERR; } } return ready; #endif } /** * Get current time, as in gettimeofday(). Use the monotonic clock if * available, to avoid problems when the system time changes. * * @param tv_sec return location for number of seconds * @param tv_usec return location for number of microseconds */ void _dbus_get_monotonic_time (long *tv_sec, long *tv_usec) { #ifdef HAVE_MONOTONIC_CLOCK struct timespec ts; clock_gettime (CLOCK_MONOTONIC, &ts); if (tv_sec) *tv_sec = ts.tv_sec; if (tv_usec) *tv_usec = ts.tv_nsec / 1000; #else struct timeval t; gettimeofday (&t, NULL); if (tv_sec) *tv_sec = t.tv_sec; if (tv_usec) *tv_usec = t.tv_usec; #endif } /** * Get current time, as in gettimeofday(). Never uses the monotonic * clock. * * @param tv_sec return location for number of seconds * @param tv_usec return location for number of microseconds */ void _dbus_get_real_time (long *tv_sec, long *tv_usec) { struct timeval t; gettimeofday (&t, NULL); if (tv_sec) *tv_sec = t.tv_sec; if (tv_usec) *tv_usec = t.tv_usec; } /** * Creates a directory; succeeds if the directory * is created or already existed. * * @param filename directory filename * @param error initialized error object * @returns #TRUE on success */ dbus_bool_t _dbus_create_directory (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (mkdir (filename_c, 0700) < 0) { if (errno == EEXIST) return TRUE; dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create directory %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } else return TRUE; } /** * Appends the given filename to the given directory. * * @todo it might be cute to collapse multiple '/' such as "foo//" * concat "//bar" * * @param dir the directory name * @param next_component the filename * @returns #TRUE on success */ dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir, const DBusString *next_component) { dbus_bool_t dir_ends_in_slash; dbus_bool_t file_starts_with_slash; if (_dbus_string_get_length (dir) == 0 || _dbus_string_get_length (next_component) == 0) return TRUE; dir_ends_in_slash = '/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1); file_starts_with_slash = '/' == _dbus_string_get_byte (next_component, 0); if (dir_ends_in_slash && file_starts_with_slash) { _dbus_string_shorten (dir, 1); } else if (!(dir_ends_in_slash || file_starts_with_slash)) { if (!_dbus_string_append_byte (dir, '/')) return FALSE; } return _dbus_string_copy (next_component, 0, dir, _dbus_string_get_length (dir)); } /** nanoseconds in a second */ #define NANOSECONDS_PER_SECOND 1000000000 /** microseconds in a second */ #define MICROSECONDS_PER_SECOND 1000000 /** milliseconds in a second */ #define MILLISECONDS_PER_SECOND 1000 /** nanoseconds in a millisecond */ #define NANOSECONDS_PER_MILLISECOND 1000000 /** microseconds in a millisecond */ #define MICROSECONDS_PER_MILLISECOND 1000 /** * Sleeps the given number of milliseconds. * @param milliseconds number of milliseconds */ void _dbus_sleep_milliseconds (int milliseconds) { #ifdef HAVE_NANOSLEEP struct timespec req; struct timespec rem; req.tv_sec = milliseconds / MILLISECONDS_PER_SECOND; req.tv_nsec = (milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND; rem.tv_sec = 0; rem.tv_nsec = 0; while (nanosleep (&req, &rem) < 0 && errno == EINTR) req = rem; #elif defined (HAVE_USLEEP) usleep (milliseconds * MICROSECONDS_PER_MILLISECOND); #else /* ! HAVE_USLEEP */ sleep (MAX (milliseconds / 1000, 1)); #endif } /** * Generates the given number of securely random bytes, * using the best mechanism we can come up with. * * @param str the string * @param n_bytes the number of random bytes to append to string * @param error location to store reason for failure * @returns #TRUE on success, #FALSE on error */ dbus_bool_t _dbus_generate_random_bytes (DBusString *str, int n_bytes, DBusError *error) { int old_len; int fd; int result; old_len = _dbus_string_get_length (str); fd = -1; /* note, urandom on linux will fall back to pseudorandom */ fd = open ("/dev/urandom", O_RDONLY); if (fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not open /dev/urandom: %s", _dbus_strerror (errno)); return FALSE; } _dbus_verbose ("/dev/urandom fd %d opened\n", fd); result = _dbus_read (fd, str, n_bytes); if (result != n_bytes) { if (result < 0) dbus_set_error (error, _dbus_error_from_errno (errno), "Could not read /dev/urandom: %s", _dbus_strerror (errno)); else dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Short read from /dev/urandom"); _dbus_close (fd, NULL); _dbus_string_set_length (str, old_len); return FALSE; } _dbus_verbose ("Read %d bytes from /dev/urandom\n", n_bytes); _dbus_close (fd, NULL); return TRUE; } /** * Exit the process, returning the given value. * * @param code the exit code */ void _dbus_exit (int code) { _exit (code); } /** * A wrapper around strerror() because some platforms * may be lame and not have strerror(). Also, never * returns NULL. * * @param error_number errno. * @returns error description. */ const char* _dbus_strerror (int error_number) { const char *msg; msg = strerror (error_number); if (msg == NULL) msg = "unknown"; return msg; } /** * signal (SIGPIPE, SIG_IGN); */ void _dbus_disable_sigpipe (void) { signal (SIGPIPE, SIG_IGN); } /** * Sets the file descriptor to be close * on exec. Should be called for all file * descriptors in D-Bus code. * * @param fd the file descriptor */ void _dbus_fd_set_close_on_exec (int fd) { int val; val = fcntl (fd, F_GETFD, 0); if (val < 0) return; val |= FD_CLOEXEC; fcntl (fd, F_SETFD, val); } /** * Closes a file descriptor. * * @param fd the file descriptor * @param error error object * @returns #FALSE if error set */ dbus_bool_t _dbus_close (int fd, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: if (close (fd) < 0) { if (errno == EINTR) goto again; dbus_set_error (error, _dbus_error_from_errno (errno), "Could not close fd %d", fd); return FALSE; } return TRUE; } /** * Duplicates a file descriptor. Makes sure the fd returned is >= 3 * (i.e. avoids stdin/stdout/stderr). Sets O_CLOEXEC. * * @param fd the file descriptor to duplicate * @param error address of error location. * @returns duplicated file descriptor * */ int _dbus_dup(int fd, DBusError *error) { int new_fd; #ifdef F_DUPFD_CLOEXEC dbus_bool_t cloexec_done; new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); cloexec_done = new_fd >= 0; if (new_fd < 0 && errno == EINVAL) #endif { new_fd = fcntl(fd, F_DUPFD, 3); } if (new_fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not duplicate fd %d", fd); return -1; } #ifdef F_DUPFD_CLOEXEC if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec(new_fd); } return new_fd; } /** * Sets a file descriptor to be nonblocking. * * @param fd the file descriptor. * @param error address of error location. * @returns #TRUE on success. */ dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket fd, DBusError *error) { return _dbus_set_fd_nonblocking (fd.fd, error); } static dbus_bool_t _dbus_set_fd_nonblocking (int fd, DBusError *error) { int val; _DBUS_ASSERT_ERROR_IS_CLEAR (error); val = fcntl (fd, F_GETFL, 0); if (val < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to get flags from file descriptor %d: %s", fd, _dbus_strerror (errno)); _dbus_verbose ("Failed to get flags for fd %d: %s\n", fd, _dbus_strerror (errno)); return FALSE; } if (fcntl (fd, F_SETFL, val | O_NONBLOCK) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set nonblocking flag of file descriptor %d: %s", fd, _dbus_strerror (errno)); _dbus_verbose ("Failed to set fd %d nonblocking: %s\n", fd, _dbus_strerror (errno)); return FALSE; } return TRUE; } /** * On GNU libc systems, print a crude backtrace to stderr. On other * systems, print "no backtrace support" and block for possible gdb * attachment if an appropriate environment variable is set. */ void _dbus_print_backtrace (void) { #if defined (HAVE_BACKTRACE) && defined (DBUS_BUILT_R_DYNAMIC) void *bt[500]; int bt_size; int i; char **syms; bt_size = backtrace (bt, 500); syms = backtrace_symbols (bt, bt_size); i = 0; while (i < bt_size) { /* don't use dbus_warn since it can _dbus_abort() */ fprintf (stderr, " %s\n", syms[i]); ++i; } fflush (stderr); free (syms); #elif defined (HAVE_BACKTRACE) && ! defined (DBUS_BUILT_R_DYNAMIC) fprintf (stderr, " D-Bus not built with -rdynamic so unable to print a backtrace\n"); #else fprintf (stderr, " D-Bus not compiled with backtrace support so unable to print a backtrace\n"); #endif } /** * Creates pair of connect sockets (as in socketpair()). * Sets both ends of the pair nonblocking. * * Marks both file descriptors as close-on-exec * * @param fd1 return location for one end * @param fd2 return location for the other end * @param blocking #TRUE if pair should be blocking * @param error error return * @returns #FALSE on failure (if error is set) */ dbus_bool_t _dbus_socketpair (DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error) { #ifdef HAVE_SOCKETPAIR int fds[2]; int retval; #ifdef SOCK_CLOEXEC dbus_bool_t cloexec_done; retval = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds); cloexec_done = retval >= 0; if (retval < 0 && (errno == EINVAL || errno == EPROTOTYPE)) #endif { retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); } if (retval < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not create full-duplex pipe"); return FALSE; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); #ifdef SOCK_CLOEXEC if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec (fds[0]); _dbus_fd_set_close_on_exec (fds[1]); } if (!blocking && (!_dbus_set_fd_nonblocking (fds[0], NULL) || !_dbus_set_fd_nonblocking (fds[1], NULL))) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not set full-duplex pipe nonblocking"); _dbus_close (fds[0], NULL); _dbus_close (fds[1], NULL); return FALSE; } fd1->fd = fds[0]; fd2->fd = fds[1]; _dbus_verbose ("full-duplex pipe %d <-> %d\n", fd1->fd, fd2->fd); return TRUE; #else _dbus_warn ("_dbus_socketpair() not implemented on this OS\n"); dbus_set_error (error, DBUS_ERROR_FAILED, "_dbus_socketpair() not implemented on this OS"); return FALSE; #endif } /** * Measure the length of the given format string and arguments, * not including the terminating nul. * * @param format a printf-style format string * @param args arguments for the format string * @returns length of the given format string and args, or -1 if no memory */ int _dbus_printf_string_upper_bound (const char *format, va_list args) { char static_buf[1024]; int bufsize = sizeof (static_buf); int len; va_list args_copy; DBUS_VA_COPY (args_copy, args); len = vsnprintf (static_buf, bufsize, format, args_copy); va_end (args_copy); /* If vsnprintf() returned non-negative, then either the string fits in * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf * returns the number of characters that were needed, or this OS returns the * truncated length. * * We ignore the possibility that snprintf might just ignore the length and * overrun the buffer (64-bit Solaris 7), because that's pathological. * If your libc is really that bad, come back when you have a better one. */ if (len == bufsize) { /* This could be the truncated length (Tru64 and IRIX have this bug), * or the real length could be coincidentally the same. Which is it? * If vsnprintf returns the truncated length, we'll go to the slow * path. */ DBUS_VA_COPY (args_copy, args); if (vsnprintf (static_buf, 1, format, args_copy) == 1) len = -1; va_end (args_copy); } /* If vsnprintf() returned negative, we have to do more work. * HP-UX returns negative. */ while (len < 0) { char *buf; bufsize *= 2; buf = dbus_malloc (bufsize); if (buf == NULL) return -1; DBUS_VA_COPY (args_copy, args); len = vsnprintf (buf, bufsize, format, args_copy); va_end (args_copy); dbus_free (buf); /* If the reported length is exactly the buffer size, round up to the * next size, in case vsnprintf has been returning the truncated * length */ if (len == bufsize) len = -1; } return len; } /** * Gets the temporary files directory by inspecting the environment variables * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned * * @returns location of temp directory, or #NULL if no memory for locking */ const char* _dbus_get_tmpdir(void) { /* Protected by _DBUS_LOCK_sysdeps */ static const char* tmpdir = NULL; if (!_DBUS_LOCK (sysdeps)) return NULL; if (tmpdir == NULL) { /* TMPDIR is what glibc uses, then * glibc falls back to the P_tmpdir macro which * just expands to "/tmp" */ if (tmpdir == NULL) tmpdir = getenv("TMPDIR"); /* These two env variables are probably * broken, but maybe some OS uses them? */ if (tmpdir == NULL) tmpdir = getenv("TMP"); if (tmpdir == NULL) tmpdir = getenv("TEMP"); /* And this is the sane fallback. */ if (tmpdir == NULL) tmpdir = "/tmp"; } _DBUS_UNLOCK (sysdeps); _dbus_assert(tmpdir != NULL); return tmpdir; } #if defined(DBUS_ENABLE_X11_AUTOLAUNCH) || defined(DBUS_ENABLE_LAUNCHD) /** * Execute a subprocess, returning up to 1024 bytes of output * into @p result. * * If successful, returns #TRUE and appends the output to @p * result. If a failure happens, returns #FALSE and * sets an error in @p error. * * @note It's not an error if the subprocess terminates normally * without writing any data to stdout. Verify the @p result length * before and after this function call to cover this case. * * @param progname initial path to exec (may or may not be absolute) * @param path_fallback if %TRUE, search PATH for executable * @param argv NULL-terminated list of arguments * @param result a DBusString where the output can be append * @param error a DBusError to store the error in case of failure * @returns #TRUE on success, #FALSE if an error happened */ static dbus_bool_t _read_subprocess_line_argv (const char *progpath, dbus_bool_t path_fallback, char * const *argv, DBusString *result, DBusError *error) { int result_pipe[2] = { -1, -1 }; int errors_pipe[2] = { -1, -1 }; pid_t pid; int ret; int status; int orig_len; dbus_bool_t retval; sigset_t new_set, old_set; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; /* We need to block any existing handlers for SIGCHLD temporarily; they * will cause waitpid() below to fail. * https://bugs.freedesktop.org/show_bug.cgi?id=21347 */ sigemptyset (&new_set); sigaddset (&new_set, SIGCHLD); sigprocmask (SIG_BLOCK, &new_set, &old_set); orig_len = _dbus_string_get_length (result); #define READ_END 0 #define WRITE_END 1 if (pipe (result_pipe) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to create a pipe to call %s: %s", progpath, _dbus_strerror (errno)); _dbus_verbose ("Failed to create a pipe to call %s: %s\n", progpath, _dbus_strerror (errno)); goto out; } if (pipe (errors_pipe) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to create a pipe to call %s: %s", progpath, _dbus_strerror (errno)); _dbus_verbose ("Failed to create a pipe to call %s: %s\n", progpath, _dbus_strerror (errno)); goto out; } pid = fork (); if (pid < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to fork() to call %s: %s", progpath, _dbus_strerror (errno)); _dbus_verbose ("Failed to fork() to call %s: %s\n", progpath, _dbus_strerror (errno)); goto out; } if (pid == 0) { /* child process */ int fd; fd = open ("/dev/null", O_RDWR); if (fd == -1) /* huh?! can't open /dev/null? */ _exit (1); _dbus_verbose ("/dev/null fd %d opened\n", fd); /* set-up stdXXX */ close (result_pipe[READ_END]); close (errors_pipe[READ_END]); if (dup2 (fd, 0) == -1) /* setup stdin */ _exit (1); if (dup2 (result_pipe[WRITE_END], 1) == -1) /* setup stdout */ _exit (1); if (dup2 (errors_pipe[WRITE_END], 2) == -1) /* setup stderr */ _exit (1); _dbus_close_all (); sigprocmask (SIG_SETMASK, &old_set, NULL); /* If it looks fully-qualified, try execv first */ if (progpath[0] == '/') { execv (progpath, argv); /* Ok, that failed. Now if path_fallback is given, let's * try unqualified. This is mostly a hack to work * around systems which ship dbus-launch in /usr/bin * but everything else in /bin (because dbus-launch * depends on X11). */ if (path_fallback) /* We must have a slash, because we checked above */ execvp (strrchr (progpath, '/')+1, argv); } else execvp (progpath, argv); /* still nothing, we failed */ _exit (1); } /* parent process */ close (result_pipe[WRITE_END]); close (errors_pipe[WRITE_END]); result_pipe[WRITE_END] = -1; errors_pipe[WRITE_END] = -1; ret = 0; do { ret = _dbus_read (result_pipe[READ_END], result, 1024); } while (ret > 0); /* reap the child process to avoid it lingering as zombie */ do { ret = waitpid (pid, &status, 0); } while (ret == -1 && errno == EINTR); /* We succeeded if the process exited with status 0 and anything was read */ if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 ) { /* The process ended with error */ DBusString error_message; if (!_dbus_string_init (&error_message)) { _DBUS_SET_OOM (error); goto out; } ret = 0; do { ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024); } while (ret > 0); _dbus_string_set_length (result, orig_len); if (_dbus_string_get_length (&error_message) > 0) dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "%s terminated abnormally with the following error: %s", progpath, _dbus_string_get_data (&error_message)); else dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "%s terminated abnormally without any error message", progpath); goto out; } retval = TRUE; out: sigprocmask (SIG_SETMASK, &old_set, NULL); if (retval) _DBUS_ASSERT_ERROR_IS_CLEAR (error); else _DBUS_ASSERT_ERROR_IS_SET (error); if (result_pipe[0] != -1) close (result_pipe[0]); if (result_pipe[1] != -1) close (result_pipe[1]); if (errors_pipe[0] != -1) close (errors_pipe[0]); if (errors_pipe[1] != -1) close (errors_pipe[1]); return retval; } #endif /** * Returns the address of a new session bus. * * If successful, returns #TRUE and appends the address to @p * address. If a failure happens, returns #FALSE and * sets an error in @p error. * * @param scope scope of autolaunch (Windows only) * @param address a DBusString where the address can be stored * @param error a DBusError to store the error in case of failure * @returns #TRUE on success, #FALSE if an error happened */ dbus_bool_t _dbus_get_autolaunch_address (const char *scope, DBusString *address, DBusError *error) { #ifdef DBUS_ENABLE_X11_AUTOLAUNCH /* Perform X11-based autolaunch. (We also support launchd-based autolaunch, * but that's done elsewhere, and if it worked, this function wouldn't * be called.) */ const char *display; char *progpath; char *argv[6]; int i; DBusString uuid; dbus_bool_t retval; if (_dbus_check_setuid ()) { dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Unable to autolaunch when setuid"); return FALSE; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; /* fd.o #19997: if $DISPLAY isn't set to something useful, then * dbus-launch-x11 is just going to fail. Rather than trying to * run it, we might as well bail out early with a nice error. * * This is not strictly true in a world where the user bus exists, * because dbus-launch --autolaunch knows how to connect to that - * but if we were going to connect to the user bus, we'd have done * so before trying autolaunch: in any case. */ display = _dbus_getenv ("DISPLAY"); if (display == NULL || display[0] == '\0') { dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Unable to autolaunch a dbus-daemon without a $DISPLAY for X11"); return FALSE; } if (!_dbus_string_init (&uuid)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_get_local_machine_uuid_encoded (&uuid, error)) { goto out; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (_dbus_getenv ("DBUS_USE_TEST_BINARY") != NULL) progpath = TEST_BUS_LAUNCH_BINARY; else #endif progpath = DBUS_BINDIR "/dbus-launch"; /* * argv[0] is always dbus-launch, that's the name what we'll * get from /proc, or ps(1), regardless what the progpath is, * see fd.o#69716 */ i = 0; argv[i] = "dbus-launch"; ++i; argv[i] = "--autolaunch"; ++i; argv[i] = _dbus_string_get_data (&uuid); ++i; argv[i] = "--binary-syntax"; ++i; argv[i] = "--close-stderr"; ++i; argv[i] = NULL; ++i; _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); retval = _read_subprocess_line_argv (progpath, TRUE, argv, address, error); out: _dbus_string_free (&uuid); return retval; #else dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Using X11 for dbus-daemon autolaunch was disabled at compile time, " "set your DBUS_SESSION_BUS_ADDRESS instead"); return FALSE; #endif } /** * Reads the uuid of the machine we're running on from * the dbus configuration. Optionally try to create it * (only root can do this usually). * * On UNIX, reads a file that gets created by dbus-uuidgen * in a post-install script. On Windows, if there's a standard * machine uuid we could just use that, but I can't find one * with the right properties (the hardware profile guid can change * without rebooting I believe). If there's no standard one * we might want to use the registry instead of a file for * this, and I'm not sure how we'd ensure the uuid gets created. * * @param machine_id guid to init with the machine's uuid * @param create_if_not_found try to create the uuid if it doesn't exist * @param error the error return * @returns #FALSE if the error is set */ dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, dbus_bool_t create_if_not_found, DBusError *error) { DBusString filename; dbus_bool_t b; _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE); b = _dbus_read_uuid_file (&filename, machine_id, FALSE, error); if (b) return TRUE; dbus_error_free (error); /* Fallback to the system machine ID */ _dbus_string_init_const (&filename, "/etc/machine-id"); b = _dbus_read_uuid_file (&filename, machine_id, FALSE, error); if (b) { /* try to copy it to the DBUS_MACHINE_UUID_FILE, but do not * complain if that isn't possible for whatever reason */ _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE); _dbus_write_uuid_file (&filename, machine_id, NULL); return TRUE; } if (!create_if_not_found) return FALSE; /* if none found, try to make a new one */ dbus_error_free (error); _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE); if (!_dbus_generate_uuid (machine_id, error)) return FALSE; return _dbus_write_uuid_file (&filename, machine_id, error); } /** * quries launchd for a specific env var which holds the socket path. * @param socket_path append the socket path to this DBusString * @param launchd_env_var the env var to look up * @param error a DBusError to store the error in case of failure * @return the value of the env var */ dbus_bool_t _dbus_lookup_launchd_socket (DBusString *socket_path, const char *launchd_env_var, DBusError *error) { #ifdef DBUS_ENABLE_LAUNCHD char *argv[4]; int i; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_dbus_check_setuid ()) { dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Unable to find launchd socket when setuid"); return FALSE; } i = 0; argv[i] = "launchctl"; ++i; argv[i] = "getenv"; ++i; argv[i] = (char*)launchd_env_var; ++i; argv[i] = NULL; ++i; _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error)) { return FALSE; } /* no error, but no result either */ if (_dbus_string_get_length(socket_path) == 0) { return FALSE; } /* strip the carriage-return */ _dbus_string_shorten(socket_path, 1); return TRUE; #else /* DBUS_ENABLE_LAUNCHD */ dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED, "can't lookup socket from launchd; launchd support not compiled in"); return FALSE; #endif } #ifdef DBUS_ENABLE_LAUNCHD static dbus_bool_t _dbus_lookup_session_address_launchd (DBusString *address, DBusError *error) { dbus_bool_t valid_socket; DBusString socket_path; if (_dbus_check_setuid ()) { dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Unable to find launchd socket when setuid"); return FALSE; } if (!_dbus_string_init (&socket_path)) { _DBUS_SET_OOM (error); return FALSE; } valid_socket = _dbus_lookup_launchd_socket (&socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error); if (dbus_error_is_set(error)) { _dbus_string_free(&socket_path); return FALSE; } if (!valid_socket) { dbus_set_error(error, "no socket path", "launchd did not provide a socket path, " "verify that org.freedesktop.dbus-session.plist is loaded!"); _dbus_string_free(&socket_path); return FALSE; } if (!_dbus_string_append (address, "unix:path=")) { _DBUS_SET_OOM (error); _dbus_string_free(&socket_path); return FALSE; } if (!_dbus_string_copy (&socket_path, 0, address, _dbus_string_get_length (address))) { _DBUS_SET_OOM (error); _dbus_string_free(&socket_path); return FALSE; } _dbus_string_free(&socket_path); return TRUE; } #endif dbus_bool_t _dbus_lookup_user_bus (dbus_bool_t *supported, DBusString *address, DBusError *error) { const char *runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR"); dbus_bool_t ret = FALSE; struct stat stbuf; DBusString user_bus_path; if (runtime_dir == NULL) { _dbus_verbose ("XDG_RUNTIME_DIR not found in environment"); *supported = FALSE; return TRUE; /* Cannot use it, but not an error */ } if (!_dbus_string_init (&user_bus_path)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append_printf (&user_bus_path, "%s/bus", runtime_dir)) { _DBUS_SET_OOM (error); goto out; } if (lstat (_dbus_string_get_const_data (&user_bus_path), &stbuf) == -1) { _dbus_verbose ("XDG_RUNTIME_DIR/bus not available: %s", _dbus_strerror (errno)); *supported = FALSE; ret = TRUE; /* Cannot use it, but not an error */ goto out; } if (stbuf.st_uid != getuid ()) { _dbus_verbose ("XDG_RUNTIME_DIR/bus owned by uid %ld, not our uid %ld", (long) stbuf.st_uid, (long) getuid ()); *supported = FALSE; ret = TRUE; /* Cannot use it, but not an error */ goto out; } if ((stbuf.st_mode & S_IFMT) != S_IFSOCK) { _dbus_verbose ("XDG_RUNTIME_DIR/bus is not a socket: st_mode = 0o%lo", (long) stbuf.st_mode); *supported = FALSE; ret = TRUE; /* Cannot use it, but not an error */ goto out; } if (!_dbus_string_append (address, "unix:path=") || !_dbus_address_append_escaped (address, &user_bus_path)) { _DBUS_SET_OOM (error); goto out; } *supported = TRUE; ret = TRUE; out: _dbus_string_free (&user_bus_path); return ret; } /** * Determines the address of the session bus by querying a * platform-specific method. * * The first parameter will be a boolean specifying whether * or not a dynamic session lookup is supported on this platform. * * If supported is TRUE and the return value is #TRUE, the * address will be appended to @p address. * If a failure happens, returns #FALSE and sets an error in * @p error. * * If supported is FALSE, ignore the return value. * * @param supported returns whether this method is supported * @param address a DBusString where the address can be stored * @param error a DBusError to store the error in case of failure * @returns #TRUE on success, #FALSE if an error happened */ dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported, DBusString *address, DBusError *error) { #ifdef DBUS_ENABLE_LAUNCHD *supported = TRUE; return _dbus_lookup_session_address_launchd (address, error); #else *supported = FALSE; if (!_dbus_lookup_user_bus (supported, address, error)) return FALSE; else if (*supported) return TRUE; /* On non-Mac Unix platforms, if the session address isn't already * set in DBUS_SESSION_BUS_ADDRESS environment variable and the * $XDG_RUNTIME_DIR/bus can't be used, we punt and fall back to the * autolaunch: global default; see init_session_address in * dbus/dbus-bus.c. */ return TRUE; #endif } /** * Called when the bus daemon is signaled to reload its configuration; any * caches should be nuked. Of course any caches that need explicit reload * are probably broken, but c'est la vie. * * */ void _dbus_flush_caches (void) { _dbus_user_database_flush_system (); } /** * Appends the directory in which a keyring for the given credentials * should be stored. The credentials should have either a Windows or * UNIX user in them. The directory should be an absolute path. * * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably * be something else, since the dotfile convention is not normal on Windows. * * @param directory string to append directory to * @param credentials credentials the directory should be for * * @returns #FALSE on no memory */ dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString *directory, DBusCredentials *credentials) { DBusString homedir; DBusString dotdir; dbus_uid_t uid; _dbus_assert (credentials != NULL); _dbus_assert (!_dbus_credentials_are_anonymous (credentials)); if (!_dbus_string_init (&homedir)) return FALSE; uid = _dbus_credentials_get_unix_uid (credentials); _dbus_assert (uid != DBUS_UID_UNSET); if (!_dbus_homedir_from_uid (uid, &homedir)) goto failed; #ifdef DBUS_ENABLE_EMBEDDED_TESTS { const char *override; override = _dbus_getenv ("DBUS_TEST_HOMEDIR"); if (override != NULL && *override != '\0') { _dbus_string_set_length (&homedir, 0); if (!_dbus_string_append (&homedir, override)) goto failed; _dbus_verbose ("Using fake homedir for testing: %s\n", _dbus_string_get_const_data (&homedir)); } else { /* Not strictly thread-safe, but if we fail at thread-safety here, * the worst that will happen is some extra warnings. */ static dbus_bool_t already_warned = FALSE; if (!already_warned) { _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n"); already_warned = TRUE; } } } #endif _dbus_string_init_const (&dotdir, ".dbus-keyrings"); if (!_dbus_concat_dir_and_file (&homedir, &dotdir)) goto failed; if (!_dbus_string_copy (&homedir, 0, directory, _dbus_string_get_length (directory))) { goto failed; } _dbus_string_free (&homedir); return TRUE; failed: _dbus_string_free (&homedir); return FALSE; } //PENDING(kdab) docs dbus_bool_t _dbus_daemon_publish_session_bus_address (const char* addr, const char *scope) { return TRUE; } //PENDING(kdab) docs void _dbus_daemon_unpublish_session_bus_address (void) { } /** * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently * for Winsock so is abstracted) * * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK */ dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (int e) { return e == EAGAIN || e == EWOULDBLOCK; } /** * Removes a directory; Directory must be empty * * @param filename directory filename * @param error initialized error object * @returns #TRUE on success */ dbus_bool_t _dbus_delete_directory (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (rmdir (filename_c) != 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to remove directory %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } return TRUE; } /** * Checks whether file descriptors may be passed via the socket * * @param fd the socket * @return TRUE when fd passing over this socket is supported * */ dbus_bool_t _dbus_socket_can_pass_unix_fd (DBusSocket fd) { #ifdef SCM_RIGHTS union { struct sockaddr sa; struct sockaddr_storage storage; struct sockaddr_un un; } sa_buf; socklen_t sa_len = sizeof(sa_buf); _DBUS_ZERO(sa_buf); if (getsockname(fd.fd, &sa_buf.sa, &sa_len) < 0) return FALSE; return sa_buf.sa.sa_family == AF_UNIX; #else return FALSE; #endif } /** * Closes all file descriptors except the first three (i.e. stdin, * stdout, stderr). */ void _dbus_close_all (void) { int maxfds, i; #ifdef __linux__ DIR *d; /* On Linux we can optimize this a bit if /proc is available. If it isn't available, fall back to the brute force way. */ d = opendir ("/proc/self/fd"); if (d) { for (;;) { struct dirent buf, *de; int k, fd; long l; char *e = NULL; k = readdir_r (d, &buf, &de); if (k != 0 || !de) break; if (de->d_name[0] == '.') continue; errno = 0; l = strtol (de->d_name, &e, 10); if (errno != 0 || e == NULL || *e != '\0') continue; fd = (int) l; if (fd < 3) continue; if (fd == dirfd (d)) continue; close (fd); } closedir (d); return; } #endif maxfds = sysconf (_SC_OPEN_MAX); /* Pick something reasonable if for some reason sysconf says * unlimited. */ if (maxfds < 0) maxfds = 1024; /* close all inherited fds */ for (i = 3; i < maxfds; i++) close (i); } /** * **NOTE**: If you modify this function, please also consider making * the corresponding change in GLib. See * glib/gutils.c:g_check_setuid(). * * Returns TRUE if the current process was executed as setuid (or an * equivalent __libc_enable_secure is available). See: * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html */ dbus_bool_t _dbus_check_setuid (void) { /* TODO: get __libc_enable_secure exported from glibc. * See http://www.openwall.com/lists/owl-dev/2012/08/14/1 */ #if 0 && defined(HAVE_LIBC_ENABLE_SECURE) { /* See glibc/include/unistd.h */ extern int __libc_enable_secure; return __libc_enable_secure; } #elif defined(HAVE_ISSETUGID) /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */ return issetugid (); #else uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ /* We call into this function from _dbus_threads_init_platform_specific() * to make sure these are initialized before we start threading. */ static dbus_bool_t check_setuid_initialised; static dbus_bool_t is_setuid; if (_DBUS_UNLIKELY (!check_setuid_initialised)) { #ifdef HAVE_GETRESUID if (getresuid (&ruid, &euid, &suid) != 0 || getresgid (&rgid, &egid, &sgid) != 0) #endif /* HAVE_GETRESUID */ { suid = ruid = getuid (); sgid = rgid = getgid (); euid = geteuid (); egid = getegid (); } check_setuid_initialised = TRUE; is_setuid = (ruid != euid || ruid != suid || rgid != egid || rgid != sgid); } return is_setuid; #endif } /** * Read the address from the socket and append it to the string * * @param fd the socket * @param address * @param error return location for error code */ dbus_bool_t _dbus_append_address_from_socket (DBusSocket fd, DBusString *address, DBusError *error) { union { struct sockaddr sa; struct sockaddr_storage storage; struct sockaddr_un un; struct sockaddr_in ipv4; struct sockaddr_in6 ipv6; } socket; char hostip[INET6_ADDRSTRLEN]; int size = sizeof (socket); DBusString path_str; if (getsockname (fd.fd, &socket.sa, &size)) goto err; switch (socket.sa.sa_family) { case AF_UNIX: if (socket.un.sun_path[0]=='\0') { _dbus_string_init_const (&path_str, &(socket.un.sun_path[1])); if (_dbus_string_append (address, "unix:abstract=") && _dbus_address_append_escaped (address, &path_str)) return TRUE; } else { _dbus_string_init_const (&path_str, socket.un.sun_path); if (_dbus_string_append (address, "unix:path=") && _dbus_address_append_escaped (address, &path_str)) return TRUE; } break; case AF_INET: if (inet_ntop (AF_INET, &socket.ipv4.sin_addr, hostip, sizeof (hostip))) if (_dbus_string_append_printf (address, "tcp:family=ipv4,host=%s,port=%u", hostip, ntohs (socket.ipv4.sin_port))) return TRUE; break; #ifdef AF_INET6 case AF_INET6: _dbus_string_init_const (&path_str, hostip); if (inet_ntop (AF_INET6, &socket.ipv6.sin6_addr, hostip, sizeof (hostip))) if (_dbus_string_append_printf (address, "tcp:family=ipv6,port=%u,host=", ntohs (socket.ipv6.sin6_port)) && _dbus_address_append_escaped (address, &path_str)) return TRUE; break; #endif default: dbus_set_error (error, _dbus_error_from_errno (EINVAL), "Failed to read address from socket: Unknown socket type."); return FALSE; } err: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open socket: %s", _dbus_strerror (errno)); return FALSE; } int _dbus_save_socket_errno (void) { return errno; } void _dbus_restore_socket_errno (int saved_errno) { errno = saved_errno; } /* tests in dbus-sysdeps-util.c */ dbus-1.10.6/dbus/dbus-pipe-unix.c0000644000175000017500000000444012602773110016511 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pipe-unix.c unix related pipe implementation * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-protocol.h" #include "dbus-string.h" #include "dbus-internals.h" #include "dbus-pipe.h" #include "dbus-sysdeps-unix.h" #include /** * write data to a pipe. * * @param pipe the pipe instance * @param buffer the buffer to write data from * @param start the first byte in the buffer to write * @param len the number of bytes to try to write * @param error error return * @returns the number of bytes written or -1 on error */ int _dbus_pipe_write (DBusPipe *pipe, const DBusString *buffer, int start, int len, DBusError *error) { int written; written = _dbus_write (pipe->fd, buffer, start, len); if (written < 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Writing to pipe: %s\n", _dbus_strerror (errno)); } return written; } /** * close a pipe. * * @param pipe the pipe instance * @param error return location for an error * @returns -1 if error is set */ int _dbus_pipe_close (DBusPipe *pipe, DBusError *error) { if (!_dbus_close (pipe->fd, error)) { return -1; } else { _dbus_pipe_invalidate (pipe); return 0; } } dbus-1.10.6/dbus/dbus-file-unix.c0000644000175000017500000002577412602773110016510 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-file-unix.c unix related file implementation (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-protocol.h" #include "dbus-errors.h" #include "dbus-file.h" #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #include #include #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif /** * Appends the contents of the given file to the string, * returning error code. At the moment, won't open a file * more than a megabyte in size. * * @param str the string to append to * @param filename filename to load * @param error place to set an error * @returns #FALSE if error was set */ dbus_bool_t _dbus_file_get_contents (DBusString *str, const DBusString *filename, DBusError *error) { int fd; struct stat sb; int orig_len; int total; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); /* O_BINARY useful on Cygwin */ fd = open (filename_c, O_RDONLY | O_BINARY); if (fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to open \"%s\": %s", filename_c, _dbus_strerror (errno)); return FALSE; } _dbus_verbose ("file fd %d opened\n", fd); if (fstat (fd, &sb) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to stat \"%s\": %s", filename_c, _dbus_strerror (errno)); _dbus_verbose ("fstat() failed: %s", _dbus_strerror (errno)); _dbus_close (fd, NULL); return FALSE; } if (sb.st_size > _DBUS_ONE_MEGABYTE) { dbus_set_error (error, DBUS_ERROR_FAILED, "File size %lu of \"%s\" is too large.", (unsigned long) sb.st_size, filename_c); _dbus_close (fd, NULL); return FALSE; } total = 0; orig_len = _dbus_string_get_length (str); if (sb.st_size > 0 && S_ISREG (sb.st_mode)) { int bytes_read; while (total < (int) sb.st_size) { bytes_read = _dbus_read (fd, str, sb.st_size - total); if (bytes_read <= 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Error reading \"%s\": %s", filename_c, _dbus_strerror (errno)); _dbus_verbose ("read() failed: %s", _dbus_strerror (errno)); _dbus_close (fd, NULL); _dbus_string_set_length (str, orig_len); return FALSE; } else total += bytes_read; } _dbus_close (fd, NULL); return TRUE; } else if (sb.st_size != 0) { _dbus_verbose ("Can only open regular files at the moment.\n"); dbus_set_error (error, DBUS_ERROR_FAILED, "\"%s\" is not a regular file", filename_c); _dbus_close (fd, NULL); return FALSE; } else { _dbus_close (fd, NULL); return TRUE; } } /** * Writes a string out to a file. If the file exists, * it will be atomically overwritten by the new data. * * @param str the string to write out * @param filename the file to save string to * @param world_readable If set, ensure the file is world readable * @param error error to be filled in on failure * @returns #FALSE on failure */ dbus_bool_t _dbus_string_save_to_file (const DBusString *str, const DBusString *filename, dbus_bool_t world_readable, DBusError *error) { int fd; int bytes_to_write; const char *filename_c; DBusString tmp_filename; const char *tmp_filename_c; int total; dbus_bool_t need_unlink; dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); fd = -1; retval = FALSE; need_unlink = FALSE; if (!_dbus_string_init (&tmp_filename)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&tmp_filename); return FALSE; } if (!_dbus_string_append (&tmp_filename, ".")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&tmp_filename); return FALSE; } #define N_TMP_FILENAME_RANDOM_BYTES 8 if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES, error)) { _dbus_string_free (&tmp_filename); return FALSE; } filename_c = _dbus_string_get_const_data (filename); tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, world_readable ? 0644 : 0600); if (fd < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not create %s: %s", tmp_filename_c, _dbus_strerror (errno)); goto out; } if (world_readable) { /* Ensure the file is world readable even in the presence of * possibly restrictive umasks; * see http://lists.freedesktop.org/archives/dbus/2010-September/013367.html */ if (fchmod (fd, 0644) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not chmod %s: %s", tmp_filename_c, _dbus_strerror (errno)); goto out; } } _dbus_verbose ("tmp file fd %d opened\n", fd); need_unlink = TRUE; total = 0; bytes_to_write = _dbus_string_get_length (str); while (total < bytes_to_write) { int bytes_written; bytes_written = _dbus_write (fd, str, total, bytes_to_write - total); if (bytes_written <= 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not write to %s: %s", tmp_filename_c, _dbus_strerror (errno)); goto out; } total += bytes_written; } if (fsync(fd)) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not synchronize file %s: %s", tmp_filename_c, _dbus_strerror (errno)); goto out; } if (!_dbus_close (fd, NULL)) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not close file %s: %s", tmp_filename_c, _dbus_strerror (errno)); goto out; } fd = -1; if (rename (tmp_filename_c, filename_c) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not rename %s to %s: %s", tmp_filename_c, filename_c, _dbus_strerror (errno)); goto out; } need_unlink = FALSE; retval = TRUE; out: /* close first, then unlink, to prevent ".nfs34234235" garbage * files */ if (fd >= 0) _dbus_close (fd, NULL); if (need_unlink && unlink (tmp_filename_c) < 0) _dbus_verbose ("Failed to unlink temp file %s: %s\n", tmp_filename_c, _dbus_strerror (errno)); _dbus_string_free (&tmp_filename); if (!retval) _DBUS_ASSERT_ERROR_IS_SET (error); return retval; } /** Makes the file readable by every user in the system. * * @param filename the filename * @param error error location * @returns #TRUE if the file's permissions could be changed. */ dbus_bool_t _dbus_make_file_world_readable(const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (chmod (filename_c, 0644) == -1) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not change permissions of file %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } return TRUE; } /** Creates the given file, failing if the file already exists. * * @param filename the filename * @param error error location * @returns #TRUE if we created the file and it didn't exist */ dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename, DBusError *error) { int fd; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, 0600); if (fd < 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create file %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } _dbus_verbose ("exclusive file fd %d opened\n", fd); if (!_dbus_close (fd, NULL)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not close file %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } return TRUE; } /** * Deletes the given file. * * @param filename the filename * @param error error location * * @returns #TRUE if unlink() succeeded */ dbus_bool_t _dbus_delete_file (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (unlink (filename_c) < 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to delete file %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } else return TRUE; } dbus-1.10.6/dbus/dbus-server-launchd.c0000644000175000017500000001552212602773110017520 0ustar00smcvsmcv00000000000000/* dbus-server-launchd.c Server methods for interacting with launchd. * Copyright (C) 2007, Tanner Lovelace * Copyright (C) 2008, Colin Walters * Copyright (C) 2008-2009, Benjamin Reed * Copyright (C) 2009, Jonas Bähr * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include "dbus-server-launchd.h" /** * @defgroup DBusServerLaunchd DBusServer implementations for Launchd * @ingroup DBusInternals * @brief Implementation details of DBusServer with Launchd support * * @{ */ #ifdef DBUS_ENABLE_LAUNCHD #include #include #include "dbus-misc.h" #include "dbus-server-socket.h" #include "dbus-sysdeps-unix.h" /* put other private launchd functions here */ #endif /* DBUS_ENABLE_LAUNCHD */ /** * @brief Creates a new server from launchd. * * launchd has allocaed a socket for us. We now query launchd for the * file descriptor of this socket and create a server on it. * In addition we inherit launchd's environment which holds a variable * containing the path to the socket. This is used to init the server's * address which is passed to autolaunched services. * * @param launchd_env_var the environment variable which holds the unix path to the socket * @param error location to store reason for failure. * @returns the new server, or #NULL on failure. */ DBusServer * _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error) { #ifdef DBUS_ENABLE_LAUNCHD DBusServer *server; DBusString address; int launchd_fd; launch_data_t sockets_dict, checkin_response; launch_data_t checkin_request; launch_data_t listening_fd_array, listening_fd; launch_data_t environment_dict, environment_param; const char *launchd_socket_path, *display; launchd_socket_path = _dbus_getenv (launchd_env_var); display = _dbus_getenv ("DISPLAY"); _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (launchd_socket_path == NULL || *launchd_socket_path == '\0') { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var); return NULL; } if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_append (&address, "unix:path=")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto l_failed_0; } if (!_dbus_string_append (&address, launchd_socket_path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto l_failed_0; } if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "launch_data_new_string(\"%s\") Unable to create string.\n", LAUNCH_KEY_CHECKIN); goto l_failed_0; } if ((checkin_response = launch_msg (checkin_request)) == NULL) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "launch_msg(\"%s\") IPC failure: %s\n", LAUNCH_KEY_CHECKIN, strerror (errno)); goto l_failed_0; } if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n", strerror (launch_data_get_errno (checkin_response))); goto l_failed_0; } sockets_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS); if (NULL == sockets_dict) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No sockets found to answer requests on!\n"); goto l_failed_0; } listening_fd_array = launch_data_dict_lookup (sockets_dict, "unix_domain_listener"); if (NULL == listening_fd_array) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No known sockets found to answer requests on!\n"); goto l_failed_0; } if (launch_data_array_get_count (listening_fd_array) != 1) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Expected 1 socket from launchd, got %d.\n", launch_data_array_get_count (listening_fd_array)); goto l_failed_0; } listening_fd = launch_data_array_get_index (listening_fd_array, 0); launchd_fd = launch_data_get_fd (listening_fd); _dbus_fd_set_close_on_exec (launchd_fd); if (launchd_fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto l_failed_0; if (display == NULL || *display == '\0') { environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); if (NULL == environment_dict) { _dbus_warn ("Unable to retrieve user environment from launchd."); } else { environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY"); if (NULL == environment_param) { _dbus_warn ("Unable to retrieve DISPLAY from launchd."); } else { display = launch_data_get_string(environment_param); dbus_setenv ("DISPLAY", display); } } } } server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0, error); if (server == NULL) { goto l_failed_0; } _dbus_string_free (&address); return server; l_failed_0: _dbus_string_free (&address); return NULL; #else /* DBUS_ENABLE_LAUNCHD */ dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "address type 'launchd' requested, but launchd support not compiled in"); return NULL; #endif } /** @} */ dbus-1.10.6/dbus/dbus-server-launchd.h0000644000175000017500000000272312602773110017524 0ustar00smcvsmcv00000000000000/* dbus-server-launchd.h Server methods for interacting with launchd. * Copyright (C) 2008, Benjamin Reed * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef DBUS_SERVER_LAUNCHD_H #define DBUS_SERVER_LAUNCHD_H #include #include DBUS_BEGIN_DECLS DBusServer * _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error); DBUS_END_DECLS #endif /* DBUS_SERVER_LAUNCHD_H */ dbus-1.10.6/dbus/dbus-string-private.h0000644000175000017500000001062212602773110017555 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-string-private.h String utility class (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_STRING_PRIVATE_H #define DBUS_STRING_PRIVATE_H #include #include #include #ifndef DBUS_CAN_USE_DBUS_STRING_PRIVATE #error "Don't go including dbus-string-private.h for no good reason" #endif DBUS_BEGIN_DECLS /** * @brief Internals of DBusString. * * DBusString internals. DBusString is an opaque objects, it must be * used via accessor functions. */ typedef struct { unsigned char *str; /**< String data, plus nul termination */ int len; /**< Length without nul */ int allocated; /**< Allocated size of data */ unsigned int constant : 1; /**< String data is not owned by DBusString */ unsigned int locked : 1; /**< DBusString has been locked and can't be changed */ unsigned int invalid : 1; /**< DBusString is invalid (e.g. already freed) */ unsigned int align_offset : 3; /**< str - align_offset is the actual malloc block */ } DBusRealString; _DBUS_STATIC_ASSERT (sizeof (DBusRealString) == sizeof (DBusString)); /** * @defgroup DBusStringInternals DBusString implementation details * @ingroup DBusInternals * @brief DBusString implementation details * * The guts of DBusString. * * @{ */ /** * The maximum length of a DBusString */ #define _DBUS_STRING_MAX_LENGTH (_DBUS_INT32_MAX - _DBUS_STRING_ALLOCATION_PADDING) /** * Checks a bunch of assertions about a string object * * @param real the DBusRealString */ #define DBUS_GENERIC_STRING_PREAMBLE(real) \ do { \ (void) real; /* might be unused unless asserting */ \ _dbus_assert ((real) != NULL); \ _dbus_assert (!(real)->invalid); \ _dbus_assert ((real)->len >= 0); \ _dbus_assert ((real)->allocated >= 0); \ _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); \ _dbus_assert ((real)->len <= _DBUS_STRING_MAX_LENGTH); \ } while (0) /** * Checks assertions about a string object that needs to be * modifiable - may not be locked or const. Also declares * the "real" variable pointing to DBusRealString. * @param str the string */ #define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ DBUS_GENERIC_STRING_PREAMBLE (real); \ _dbus_assert (!(real)->constant); \ _dbus_assert (!(real)->locked) /** * Checks assertions about a string object that may be locked but * can't be const. i.e. a string object that we can free. Also * declares the "real" variable pointing to DBusRealString. * * @param str the string */ #define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ DBUS_GENERIC_STRING_PREAMBLE (real); \ _dbus_assert (!(real)->constant) /** * Checks assertions about a string that may be const or locked. Also * declares the "real" variable pointing to DBusRealString. * @param str the string. */ #define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \ DBUS_GENERIC_STRING_PREAMBLE (real) /** * Checks for ASCII blank byte * @param c the byte */ #define DBUS_IS_ASCII_BLANK(c) ((c) == ' ' || (c) == '\t') /** * Checks for ASCII whitespace byte * @param c the byte */ #define DBUS_IS_ASCII_WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r') /** @} */ DBUS_END_DECLS #endif /* DBUS_STRING_PRIVATE_H */ dbus-1.10.6/dbus/dbus-string.h0000644000175000017500000005130712602773110016112 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-string.h String utility class (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2006 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_STRING_H #define DBUS_STRING_H #include #include #include #include DBUS_BEGIN_DECLS /** * DBusString object */ typedef struct DBusString DBusString; struct DBusString { #if defined(DBUS_WIN) && defined(_DEBUG) const char *dummy1; /**< placeholder */ #else const void *dummy1; /**< placeholder */ #endif int dummy2; /**< placeholder */ int dummy3; /**< placeholder */ unsigned int dummy_bit1 : 1; /**< placeholder */ unsigned int dummy_bit2 : 1; /**< placeholder */ unsigned int dummy_bit3 : 1; /**< placeholder */ unsigned int dummy_bits : 3; /**< placeholder */ }; #ifdef DBUS_DISABLE_ASSERT /* Some simple inlining hacks; the current linker is not smart enough * to inline non-exported symbols across files in the library. * Note that these break type safety (due to the casts) */ #define _dbus_string_get_data(s) ((char*)(((DBusString*)(s))->dummy1)) #define _dbus_string_get_length(s) (((DBusString*)(s))->dummy2) #define _dbus_string_set_byte(s, i, b) ((((unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) = (unsigned char) (b)) #define _dbus_string_get_byte(s, i) (((const unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) #define _dbus_string_get_const_data(s) ((const char*)(((DBusString*)(s))->dummy1)) #define _dbus_string_get_const_data_len(s,start,len) (((const char*)(((DBusString*)(s))->dummy1)) + (start)) #endif DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_init (DBusString *str); DBUS_PRIVATE_EXPORT void _dbus_string_init_const (DBusString *str, const char *value); DBUS_PRIVATE_EXPORT void _dbus_string_init_const_len (DBusString *str, const char *value, int len); dbus_bool_t _dbus_string_init_preallocated (DBusString *str, int allocate_size); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_init_from_string (DBusString *str, const DBusString *from); DBUS_PRIVATE_EXPORT void _dbus_string_free (DBusString *str); void _dbus_string_lock (DBusString *str); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_compact (DBusString *str, int max_waste); #ifndef _dbus_string_get_data DBUS_PRIVATE_EXPORT char* _dbus_string_get_data (DBusString *str); #endif /* _dbus_string_get_data */ #ifndef _dbus_string_get_const_data DBUS_PRIVATE_EXPORT const char* _dbus_string_get_const_data (const DBusString *str); #endif /* _dbus_string_get_const_data */ char* _dbus_string_get_data_len (DBusString *str, int start, int len); #ifndef _dbus_string_get_const_data_len DBUS_PRIVATE_EXPORT const char* _dbus_string_get_const_data_len (const DBusString *str, int start, int len); #endif #ifndef _dbus_string_set_byte DBUS_PRIVATE_EXPORT void _dbus_string_set_byte (DBusString *str, int i, unsigned char byte); #endif #ifndef _dbus_string_get_byte DBUS_PRIVATE_EXPORT unsigned char _dbus_string_get_byte (const DBusString *str, int start); #endif /* _dbus_string_get_byte */ DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_insert_bytes (DBusString *str, int i, int n_bytes, unsigned char byte); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_insert_byte (DBusString *str, int i, unsigned char byte); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_steal_data (DBusString *str, char **data_return); dbus_bool_t _dbus_string_steal_data_len (DBusString *str, char **data_return, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_copy_data (const DBusString *str, char **data_return); dbus_bool_t _dbus_string_copy_data_len (const DBusString *str, char **data_return, int start, int len); void _dbus_string_copy_to_buffer (const DBusString *str, char *buffer, int len); DBUS_PRIVATE_EXPORT void _dbus_string_copy_to_buffer_with_nul (const DBusString *str, char *buffer, int avail_len); #ifndef _dbus_string_get_length DBUS_PRIVATE_EXPORT int _dbus_string_get_length (const DBusString *str); #endif /* !_dbus_string_get_length */ /** * Get the string's length as an unsigned integer, for comparison with * size_t and similar unsigned types that does not trigger compiler * warnings about potential value changes during conversion. * * DBusString lengths are signed for historical reasons, but we know that * the length is always >= 0 (and DBUS_GENERIC_STRING_PREAMBLE asserts * that this is the case) so we know that this cast does not change the * value. */ static inline unsigned int _dbus_string_get_length_uint (const DBusString *str) { return (unsigned int) _dbus_string_get_length (str); } DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_lengthen (DBusString *str, int additional_length); DBUS_PRIVATE_EXPORT void _dbus_string_shorten (DBusString *str, int length_to_remove); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_set_length (DBusString *str, int length); dbus_bool_t _dbus_string_align_length (DBusString *str, int alignment); dbus_bool_t _dbus_string_alloc_space (DBusString *str, int extra_bytes); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append (DBusString *str, const char *buffer); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_len (DBusString *str, const char *buffer, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_int (DBusString *str, long value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_uint (DBusString *str, unsigned long value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_byte (DBusString *str, unsigned char byte); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_printf (DBusString *str, const char *format, ...) _DBUS_GNUC_PRINTF (2, 3); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_append_printf_valist (DBusString *str, const char *format, va_list args); dbus_bool_t _dbus_string_insert_2_aligned (DBusString *str, int insert_at, const unsigned char octets[2]); dbus_bool_t _dbus_string_insert_4_aligned (DBusString *str, int insert_at, const unsigned char octets[4]); dbus_bool_t _dbus_string_insert_8_aligned (DBusString *str, int insert_at, const unsigned char octets[8]); dbus_bool_t _dbus_string_insert_alignment (DBusString *str, int *insert_at, int alignment); DBUS_PRIVATE_EXPORT void _dbus_string_delete (DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_move (DBusString *source, int start, DBusString *dest, int insert_at); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_copy (const DBusString *source, int start, DBusString *dest, int insert_at); dbus_bool_t _dbus_string_move_len (DBusString *source, int start, int len, DBusString *dest, int insert_at); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_copy_len (const DBusString *source, int start, int len, DBusString *dest, int insert_at); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_replace_len (const DBusString *source, int start, int len, DBusString *dest, int replace_at, int replace_len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_split_on_byte (DBusString *source, unsigned char byte, DBusString *tail); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_parse_int (const DBusString *str, int start, long *value_return, int *end_return); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_parse_uint (const DBusString *str, int start, unsigned long *value_return, int *end_return); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_find (const DBusString *str, int start, const char *substr, int *found); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_find_eol (const DBusString *str, int start, int *found, int *found_len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_find_to (const DBusString *str, int start, int end, const char *substr, int *found); dbus_bool_t _dbus_string_find_byte_backward (const DBusString *str, int start, unsigned char byte, int *found); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_find_blank (const DBusString *str, int start, int *found); DBUS_PRIVATE_EXPORT void _dbus_string_skip_blank (const DBusString *str, int start, int *end); DBUS_PRIVATE_EXPORT void _dbus_string_skip_white (const DBusString *str, int start, int *end); void _dbus_string_skip_white_reverse (const DBusString *str, int end, int *start); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_equal (const DBusString *a, const DBusString *b); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_equal_c_str (const DBusString *a, const char *c_str); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_equal_len (const DBusString *a, const DBusString *b, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_equal_substring (const DBusString *a, int a_start, int a_len, const DBusString *b, int b_start); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_starts_with_c_str (const DBusString *a, const char *c_str); dbus_bool_t _dbus_string_ends_with_c_str (const DBusString *a, const char *c_str); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_pop_line (DBusString *source, DBusString *dest); DBUS_PRIVATE_EXPORT void _dbus_string_delete_first_word (DBusString *str); DBUS_PRIVATE_EXPORT void _dbus_string_delete_leading_blanks (DBusString *str); DBUS_PRIVATE_EXPORT void _dbus_string_chop_white (DBusString *str); dbus_bool_t _dbus_string_append_byte_as_hex (DBusString *str, unsigned char byte); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_hex_encode (const DBusString *source, int start, DBusString *dest, int insert_at); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_hex_decode (const DBusString *source, int start, int *end_return, DBusString *dest, int insert_at); DBUS_PRIVATE_EXPORT void _dbus_string_tolower_ascii (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT void _dbus_string_toupper_ascii (const DBusString *str, int start, int len); dbus_bool_t _dbus_string_validate_ascii (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_validate_nul (const DBusString *str, int start, int len); void _dbus_string_zero (DBusString *str); /** * We allocate 1 byte for nul termination, plus 7 bytes for possible * align_offset, so we always need 8 bytes on top of the string's * length to be in the allocated block. */ #define _DBUS_STRING_ALLOCATION_PADDING 8 /** * Defines a static const variable with type #DBusString called "name" * containing the given string literal. * * @param name the name of the variable * @param str the string value */ #define _DBUS_STRING_DEFINE_STATIC(name, str) \ static const char _dbus_static_string_##name[] = str; \ static const DBusString name = { _dbus_static_string_##name, \ sizeof(_dbus_static_string_##name), \ sizeof(_dbus_static_string_##name) + \ _DBUS_STRING_ALLOCATION_PADDING, \ TRUE, TRUE, FALSE, 0 } DBUS_END_DECLS #endif /* DBUS_STRING_H */ dbus-1.10.6/dbus/dbus-string.c0000644000175000017500000021337512602773110016112 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-string.c String utility class (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. * Copyright (C) 2006 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-string.h" /* we allow a system header here, for speed/convenience */ #include /* for vsnprintf */ #include #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 #include "dbus-string-private.h" #include "dbus-marshal-basic.h" /* probably should be removed by moving the usage of DBUS_TYPE * into the marshaling-related files */ /* for DBUS_VA_COPY */ #include "dbus-sysdeps.h" /** * @defgroup DBusString DBusString class * @ingroup DBusInternals * @brief DBusString data structure for safer string handling * * Types and functions related to DBusString. DBusString is intended * to be a string class that makes it hard to mess up security issues * (and just in general harder to write buggy code). It should be * used (or extended and then used) rather than the libc stuff in * string.h. The string class is a bit inconvenient at spots because * it handles out-of-memory failures and tries to be extra-robust. * * A DBusString has a maximum length set at initialization time; this * can be used to ensure that a buffer doesn't get too big. The * _dbus_string_lengthen() method checks for overflow, and for max * length being exceeded. * * Try to avoid conversion to a plain C string, i.e. add methods on * the string object instead, only convert to C string when passing * things out to the public API. In particular, no sprintf, strcpy, * strcat, any of that should be used. The GString feature of * accepting negative numbers for "length of string" is also absent, * because it could keep us from detecting bogus huge lengths. i.e. if * we passed in some bogus huge length it would be taken to mean * "current length of string" instead of "broken crack" * * @todo #DBusString needs a lot of cleaning up; some of the * API is no longer used, and the API is pretty inconsistent. * In particular all the "append" APIs, especially those involving * alignment but probably lots of them, are no longer used by the * marshaling code which always does "inserts" now. */ /** * @addtogroup DBusString * @{ */ static void fixup_alignment (DBusRealString *real) { unsigned char *aligned; unsigned char *real_block; unsigned int old_align_offset; /* we have to have extra space in real->allocated for the align offset and nul byte */ _dbus_assert (real->len <= real->allocated - _DBUS_STRING_ALLOCATION_PADDING); old_align_offset = real->align_offset; real_block = real->str - old_align_offset; aligned = _DBUS_ALIGN_ADDRESS (real_block, 8); real->align_offset = aligned - real_block; real->str = aligned; if (old_align_offset != real->align_offset) { /* Here comes the suck */ memmove (real_block + real->align_offset, real_block + old_align_offset, real->len + 1); } _dbus_assert (real->align_offset < 8); _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str); } static void undo_alignment (DBusRealString *real) { if (real->align_offset != 0) { memmove (real->str - real->align_offset, real->str, real->len + 1); real->str = real->str - real->align_offset; real->align_offset = 0; } } /** * Initializes a string that can be up to the given allocation size * before it has to realloc. The string starts life with zero length. * The string must eventually be freed with _dbus_string_free(). * * @param str memory to hold the string * @param allocate_size amount to preallocate * @returns #TRUE on success, #FALSE if no memory */ dbus_bool_t _dbus_string_init_preallocated (DBusString *str, int allocate_size) { DBusRealString *real; _DBUS_STATIC_ASSERT (sizeof (DBusString) == sizeof (DBusRealString)); _dbus_assert (str != NULL); real = (DBusRealString*) str; /* It's very important not to touch anything * other than real->str if we're going to fail, * since we also use this function to reset * an existing string, e.g. in _dbus_string_steal_data() */ real->str = dbus_malloc (_DBUS_STRING_ALLOCATION_PADDING + allocate_size); if (real->str == NULL) return FALSE; real->allocated = _DBUS_STRING_ALLOCATION_PADDING + allocate_size; real->len = 0; real->str[real->len] = '\0'; real->constant = FALSE; real->locked = FALSE; real->invalid = FALSE; real->align_offset = 0; fixup_alignment (real); return TRUE; } /** * Initializes a string. The string starts life with zero length. The * string must eventually be freed with _dbus_string_free(). * * @param str memory to hold the string * @returns #TRUE on success, #FALSE if no memory */ dbus_bool_t _dbus_string_init (DBusString *str) { return _dbus_string_init_preallocated (str, 0); } /** * Initializes a constant string. The value parameter is not copied * (should be static), and the string may never be modified. * It is safe but not necessary to call _dbus_string_free() * on a const string. The string has a length limit of MAXINT - 8. * * @param str memory to use for the string * @param value a string to be stored in str (not copied!!!) */ void _dbus_string_init_const (DBusString *str, const char *value) { _dbus_assert (value != NULL); _dbus_string_init_const_len (str, value, strlen (value)); } /** * Initializes a constant string with a length. The value parameter is * not copied (should be static), and the string may never be * modified. It is safe but not necessary to call _dbus_string_free() * on a const string. * * @param str memory to use for the string * @param value a string to be stored in str (not copied!!!) * @param len the length to use */ void _dbus_string_init_const_len (DBusString *str, const char *value, int len) { DBusRealString *real; _dbus_assert (str != NULL); _dbus_assert (len == 0 || value != NULL); _dbus_assert (len <= _DBUS_STRING_MAX_LENGTH); _dbus_assert (len >= 0); real = (DBusRealString*) str; real->str = (unsigned char*) value; real->len = len; real->allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */ real->constant = TRUE; real->locked = TRUE; real->invalid = FALSE; real->align_offset = 0; /* We don't require const strings to be 8-byte aligned as the * memory is coming from elsewhere. */ } /** * Initializes a string from another string. The * string must eventually be freed with _dbus_string_free(). * * @param str memory to hold the string * @param from instance from which the string is initialized * @returns #TRUE on success, #FALSE if no memory */ dbus_bool_t _dbus_string_init_from_string(DBusString *str, const DBusString *from) { if (!_dbus_string_init (str)) return FALSE; return _dbus_string_append (str, _dbus_string_get_const_data (from)); } /** * Frees a string created by _dbus_string_init(). * * @param str memory where the string is stored. */ void _dbus_string_free (DBusString *str) { DBusRealString *real = (DBusRealString*) str; DBUS_GENERIC_STRING_PREAMBLE (real); if (real->constant) return; /* so it's safe if @p str returned by a failed * _dbus_string_init call * Bug: https://bugs.freedesktop.org/show_bug.cgi?id=65959 */ if (real->str == NULL) return; dbus_free (real->str - real->align_offset); real->invalid = TRUE; } static dbus_bool_t compact (DBusRealString *real, int max_waste) { unsigned char *new_str; int new_allocated; int waste; waste = real->allocated - (real->len + _DBUS_STRING_ALLOCATION_PADDING); if (waste <= max_waste) return TRUE; new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; new_str = dbus_realloc (real->str - real->align_offset, new_allocated); if (_DBUS_UNLIKELY (new_str == NULL)) return FALSE; real->str = new_str + real->align_offset; real->allocated = new_allocated; fixup_alignment (real); return TRUE; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /* Not using this feature at the moment, * so marked DBUS_ENABLE_EMBEDDED_TESTS-only */ /** * Locks a string such that any attempts to change the string will * result in aborting the program. Also, if the string is wasting a * lot of memory (allocation is sufficiently larger than what the * string is really using), _dbus_string_lock() will realloc the * string's data to "compact" it. * * @param str the string to lock. */ void _dbus_string_lock (DBusString *str) { DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */ real->locked = TRUE; /* Try to realloc to avoid excess memory usage, since * we know we won't change the string further */ #define MAX_WASTE 48 compact (real, MAX_WASTE); } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ static dbus_bool_t reallocate_for_length (DBusRealString *real, int new_length) { int new_allocated; unsigned char *new_str; /* at least double our old allocation to avoid O(n), avoiding * overflow */ if (real->allocated > (_DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2) new_allocated = _DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING; else new_allocated = real->allocated * 2; /* if you change the code just above here, run the tests without * the following assert-only hack before you commit */ /* This is keyed off asserts in addition to tests so when you * disable asserts to profile, you don't get this destroyer * of profiles. */ #if defined (DBUS_ENABLE_EMBEDDED_TESTS) && !defined (DBUS_DISABLE_ASSERT) new_allocated = 0; /* ensure a realloc every time so that we go * through all malloc failure codepaths */ #endif /* But be sure we always alloc at least space for the new length */ new_allocated = MAX (new_allocated, new_length + _DBUS_STRING_ALLOCATION_PADDING); _dbus_assert (new_allocated >= real->allocated); /* code relies on this */ new_str = dbus_realloc (real->str - real->align_offset, new_allocated); if (_DBUS_UNLIKELY (new_str == NULL)) return FALSE; real->str = new_str + real->align_offset; real->allocated = new_allocated; fixup_alignment (real); return TRUE; } /** * Compacts the string to avoid wasted memory. Wasted memory is * memory that is allocated but not actually required to store the * current length of the string. The compact is only done if more * than the given amount of memory is being wasted (otherwise the * waste is ignored and the call does nothing). * * @param str the string * @param max_waste the maximum amount of waste to ignore * @returns #FALSE if the compact failed due to realloc failure */ dbus_bool_t _dbus_string_compact (DBusString *str, int max_waste) { DBUS_STRING_PREAMBLE (str); return compact (real, max_waste); } static dbus_bool_t set_length (DBusRealString *real, int new_length) { /* Note, we are setting the length not including nul termination */ /* exceeding max length is the same as failure to allocate memory */ if (_DBUS_UNLIKELY (new_length > _DBUS_STRING_MAX_LENGTH)) return FALSE; else if (new_length > (real->allocated - _DBUS_STRING_ALLOCATION_PADDING) && _DBUS_UNLIKELY (!reallocate_for_length (real, new_length))) return FALSE; else { real->len = new_length; real->str[new_length] = '\0'; return TRUE; } } static dbus_bool_t open_gap (int len, DBusRealString *dest, int insert_at) { if (len == 0) return TRUE; if (len > _DBUS_STRING_MAX_LENGTH - dest->len) return FALSE; /* detected overflow of dest->len + len below */ if (!set_length (dest, dest->len + len)) return FALSE; memmove (dest->str + insert_at + len, dest->str + insert_at, dest->len - len - insert_at); return TRUE; } #ifndef _dbus_string_get_data /** * Gets the raw character buffer from the string. The returned buffer * will be nul-terminated, but note that strings may contain binary * data so there may be extra nul characters prior to the termination. * This function should be little-used, extend DBusString or add * stuff to dbus-sysdeps.c instead. It's an error to use this * function on a const string. * * @param str the string * @returns the data */ char* _dbus_string_get_data (DBusString *str) { DBUS_STRING_PREAMBLE (str); return (char*) real->str; } #endif /* _dbus_string_get_data */ /* only do the function if we don't have the macro */ #ifndef _dbus_string_get_const_data /** * Gets the raw character buffer from a const string. * * @param str the string * @returns the string data */ const char* _dbus_string_get_const_data (const DBusString *str) { DBUS_CONST_STRING_PREAMBLE (str); return (const char*) real->str; } #endif /* _dbus_string_get_const_data */ /** * Gets a sub-portion of the raw character buffer from the * string. The "len" field is required simply for error * checking, to be sure you don't try to use more * string than exists. The nul termination of the * returned buffer remains at the end of the entire * string, not at start + len. * * @param str the string * @param start byte offset to return * @param len length of segment to return * @returns the string data */ char* _dbus_string_get_data_len (DBusString *str, int start, int len) { DBUS_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= real->len); _dbus_assert (len <= real->len - start); return (char*) real->str + start; } /* only do the function if we don't have the macro */ #ifndef _dbus_string_get_const_data_len /** * const version of _dbus_string_get_data_len(). * * @param str the string * @param start byte offset to return * @param len length of segment to return * @returns the string data */ const char* _dbus_string_get_const_data_len (const DBusString *str, int start, int len) { DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= real->len); _dbus_assert (len <= real->len - start); return (const char*) real->str + start; } #endif /* _dbus_string_get_const_data_len */ /* only do the function if we don't have the macro */ #ifndef _dbus_string_set_byte /** * Sets the value of the byte at the given position. * * @param str the string * @param i the position * @param byte the new value */ void _dbus_string_set_byte (DBusString *str, int i, unsigned char byte) { DBUS_STRING_PREAMBLE (str); _dbus_assert (i < real->len); _dbus_assert (i >= 0); real->str[i] = byte; } #endif /* _dbus_string_set_byte */ /* only have the function if we didn't create a macro */ #ifndef _dbus_string_get_byte /** * Gets the byte at the given position. It is * allowed to ask for the nul byte at the end of * the string. * * @param str the string * @param start the position * @returns the byte at that position */ unsigned char _dbus_string_get_byte (const DBusString *str, int start) { DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); return real->str[start]; } #endif /* _dbus_string_get_byte */ /** * Inserts a number of bytes of a given value at the * given position. * * @param str the string * @param i the position * @param n_bytes number of bytes * @param byte the value to insert * @returns #TRUE on success */ dbus_bool_t _dbus_string_insert_bytes (DBusString *str, int i, int n_bytes, unsigned char byte) { DBUS_STRING_PREAMBLE (str); _dbus_assert (i <= real->len); _dbus_assert (i >= 0); _dbus_assert (n_bytes >= 0); if (n_bytes == 0) return TRUE; if (!open_gap (n_bytes, real, i)) return FALSE; memset (real->str + i, byte, n_bytes); return TRUE; } /** * Inserts a single byte at the given position. * * @param str the string * @param i the position * @param byte the value to insert * @returns #TRUE on success */ dbus_bool_t _dbus_string_insert_byte (DBusString *str, int i, unsigned char byte) { DBUS_STRING_PREAMBLE (str); _dbus_assert (i <= real->len); _dbus_assert (i >= 0); if (!open_gap (1, real, i)) return FALSE; real->str[i] = byte; return TRUE; } /** * Like _dbus_string_get_data(), but removes the * gotten data from the original string. The caller * must free the data returned. This function may * fail due to lack of memory, and return #FALSE. * * @param str the string * @param data_return location to return the buffer * @returns #TRUE on success */ dbus_bool_t _dbus_string_steal_data (DBusString *str, char **data_return) { DBUS_STRING_PREAMBLE (str); _dbus_assert (data_return != NULL); undo_alignment (real); *data_return = (char*) real->str; /* reset the string */ if (!_dbus_string_init (str)) { /* hrm, put it back then */ real->str = (unsigned char*) *data_return; *data_return = NULL; fixup_alignment (real); return FALSE; } return TRUE; } /** * Copies the data from the string into a char* * * @param str the string * @param data_return place to return the data * @returns #TRUE on success, #FALSE on no memory */ dbus_bool_t _dbus_string_copy_data (const DBusString *str, char **data_return) { DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (data_return != NULL); *data_return = dbus_malloc (real->len + 1); if (*data_return == NULL) return FALSE; memcpy (*data_return, real->str, real->len + 1); return TRUE; } /** * Copies the contents of a DBusString into a different buffer. It is * a bug if avail_len is too short to hold the string contents. nul * termination is not copied, just the supplied bytes. * * @param str a string * @param buffer a C buffer to copy data to * @param avail_len maximum length of C buffer */ void _dbus_string_copy_to_buffer (const DBusString *str, char *buffer, int avail_len) { DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (avail_len >= 0); _dbus_assert (avail_len >= real->len); memcpy (buffer, real->str, real->len); } /** * Copies the contents of a DBusString into a different buffer. It is * a bug if avail_len is too short to hold the string contents plus a * nul byte. * * @param str a string * @param buffer a C buffer to copy data to * @param avail_len maximum length of C buffer */ void _dbus_string_copy_to_buffer_with_nul (const DBusString *str, char *buffer, int avail_len) { DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (avail_len >= 0); _dbus_assert (avail_len > real->len); memcpy (buffer, real->str, real->len+1); } /* Only have the function if we don't have the macro */ #ifndef _dbus_string_get_length /** * Gets the length of a string (not including nul termination). * * @returns the length. */ int _dbus_string_get_length (const DBusString *str) { DBUS_CONST_STRING_PREAMBLE (str); return real->len; } #endif /* !_dbus_string_get_length */ /** * Makes a string longer by the given number of bytes. Checks whether * adding additional_length to the current length would overflow an * integer, and checks for exceeding a string's max length. * The new bytes are not initialized, other than nul-terminating * the end of the string. The uninitialized bytes may contain * nul bytes or other junk. * * @param str a string * @param additional_length length to add to the string. * @returns #TRUE on success. */ dbus_bool_t _dbus_string_lengthen (DBusString *str, int additional_length) { DBUS_STRING_PREAMBLE (str); _dbus_assert (additional_length >= 0); if (_DBUS_UNLIKELY (additional_length > _DBUS_STRING_MAX_LENGTH - real->len)) return FALSE; /* would overflow */ return set_length (real, real->len + additional_length); } /** * Makes a string shorter by the given number of bytes. * * @param str a string * @param length_to_remove length to remove from the string. */ void _dbus_string_shorten (DBusString *str, int length_to_remove) { DBUS_STRING_PREAMBLE (str); _dbus_assert (length_to_remove >= 0); _dbus_assert (length_to_remove <= real->len); set_length (real, real->len - length_to_remove); } /** * Sets the length of a string. Can be used to truncate or lengthen * the string. If the string is lengthened, the function may fail and * return #FALSE. Newly-added bytes are not initialized, as with * _dbus_string_lengthen(). * * @param str a string * @param length new length of the string. * @returns #FALSE on failure. */ dbus_bool_t _dbus_string_set_length (DBusString *str, int length) { DBUS_STRING_PREAMBLE (str); _dbus_assert (length >= 0); return set_length (real, length); } static dbus_bool_t align_insert_point_then_open_gap (DBusString *str, int *insert_at_p, int alignment, int gap_size) { unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */ unsigned long gap_pos; int insert_at; int delta; DBUS_STRING_PREAMBLE (str); _dbus_assert (alignment >= 1); _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */ insert_at = *insert_at_p; _dbus_assert (insert_at <= real->len); gap_pos = _DBUS_ALIGN_VALUE (insert_at, alignment); new_len = real->len + (gap_pos - insert_at) + gap_size; if (_DBUS_UNLIKELY (new_len > (unsigned long) _DBUS_STRING_MAX_LENGTH)) return FALSE; delta = new_len - real->len; _dbus_assert (delta >= 0); if (delta == 0) /* only happens if gap_size == 0 and insert_at is aligned already */ { _dbus_assert (((unsigned long) *insert_at_p) == gap_pos); return TRUE; } if (_DBUS_UNLIKELY (!open_gap (new_len - real->len, real, insert_at))) return FALSE; /* nul the padding if we had to add any padding */ if (gap_size < delta) { memset (&real->str[insert_at], '\0', gap_pos - insert_at); } *insert_at_p = gap_pos; return TRUE; } static dbus_bool_t align_length_then_lengthen (DBusString *str, int alignment, int then_lengthen_by) { int insert_at; insert_at = _dbus_string_get_length (str); return align_insert_point_then_open_gap (str, &insert_at, alignment, then_lengthen_by); } /** * Align the length of a string to a specific alignment (typically 4 or 8) * by appending nul bytes to the string. * * @param str a string * @param alignment the alignment * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_align_length (DBusString *str, int alignment) { return align_length_then_lengthen (str, alignment, 0); } /** * Preallocate extra_bytes such that a future lengthening of the * string by extra_bytes is guaranteed to succeed without an out of * memory error. * * @param str a string * @param extra_bytes bytes to alloc * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_alloc_space (DBusString *str, int extra_bytes) { if (!_dbus_string_lengthen (str, extra_bytes)) return FALSE; _dbus_string_shorten (str, extra_bytes); return TRUE; } static dbus_bool_t append (DBusRealString *real, const char *buffer, int buffer_len) { if (buffer_len == 0) return TRUE; if (!_dbus_string_lengthen ((DBusString*)real, buffer_len)) return FALSE; memcpy (real->str + (real->len - buffer_len), buffer, buffer_len); return TRUE; } /** * Appends a nul-terminated C-style string to a DBusString. * * @param str the DBusString * @param buffer the nul-terminated characters to append * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_append (DBusString *str, const char *buffer) { unsigned long buffer_len; DBUS_STRING_PREAMBLE (str); _dbus_assert (buffer != NULL); buffer_len = strlen (buffer); if (buffer_len > (unsigned long) _DBUS_STRING_MAX_LENGTH) return FALSE; return append (real, buffer, buffer_len); } /** assign 2 bytes from one string to another */ #define ASSIGN_2_OCTETS(p, octets) \ *((dbus_uint16_t*)(p)) = *((dbus_uint16_t*)(octets)); /** assign 4 bytes from one string to another */ #define ASSIGN_4_OCTETS(p, octets) \ *((dbus_uint32_t*)(p)) = *((dbus_uint32_t*)(octets)); /** assign 8 bytes from one string to another */ #define ASSIGN_8_OCTETS(p, octets) \ *((dbus_uint64_t*)(p)) = *((dbus_uint64_t*)(octets)); /** * Inserts 2 bytes aligned on a 2 byte boundary * with any alignment padding initialized to 0. * * @param str the DBusString * @param insert_at where to insert * @param octets 2 bytes to insert * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_insert_2_aligned (DBusString *str, int insert_at, const unsigned char octets[2]) { DBUS_STRING_PREAMBLE (str); if (!align_insert_point_then_open_gap (str, &insert_at, 2, 2)) return FALSE; ASSIGN_2_OCTETS (real->str + insert_at, octets); return TRUE; } /** * Inserts 4 bytes aligned on a 4 byte boundary * with any alignment padding initialized to 0. * * @param str the DBusString * @param insert_at where to insert * @param octets 4 bytes to insert * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_insert_4_aligned (DBusString *str, int insert_at, const unsigned char octets[4]) { DBUS_STRING_PREAMBLE (str); if (!align_insert_point_then_open_gap (str, &insert_at, 4, 4)) return FALSE; ASSIGN_4_OCTETS (real->str + insert_at, octets); return TRUE; } /** * Inserts 8 bytes aligned on an 8 byte boundary * with any alignment padding initialized to 0. * * @param str the DBusString * @param insert_at where to insert * @param octets 8 bytes to insert * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_insert_8_aligned (DBusString *str, int insert_at, const unsigned char octets[8]) { DBUS_STRING_PREAMBLE (str); if (!align_insert_point_then_open_gap (str, &insert_at, 8, 8)) return FALSE; _dbus_assert (_DBUS_ALIGN_VALUE (insert_at, 8) == (unsigned) insert_at); ASSIGN_8_OCTETS (real->str + insert_at, octets); return TRUE; } /** * Inserts padding at *insert_at such to align it to the given * boundary. Initializes the padding to nul bytes. Sets *insert_at * to the aligned position. * * @param str the DBusString * @param insert_at location to be aligned * @param alignment alignment boundary (1, 2, 4, or 8) * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_insert_alignment (DBusString *str, int *insert_at, int alignment) { DBUS_STRING_PREAMBLE (str); if (!align_insert_point_then_open_gap (str, insert_at, alignment, 0)) return FALSE; _dbus_assert (_DBUS_ALIGN_VALUE (*insert_at, alignment) == (unsigned) *insert_at); return TRUE; } /** * Appends a printf-style formatted string * to the #DBusString. * * @param str the string * @param format printf format * @param args variable argument list * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_append_printf_valist (DBusString *str, const char *format, va_list args) { dbus_bool_t ret = FALSE; int len; va_list args_copy; DBUS_STRING_PREAMBLE (str); DBUS_VA_COPY (args_copy, args); /* Measure the message length without terminating nul */ len = _dbus_printf_string_upper_bound (format, args); if (len < 0) goto out; if (!_dbus_string_lengthen (str, len)) { goto out; } vsprintf ((char*) (real->str + (real->len - len)), format, args_copy); ret = TRUE; out: va_end (args_copy); return ret; } /** * Appends a printf-style formatted string * to the #DBusString. * * @param str the string * @param format printf format * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_append_printf (DBusString *str, const char *format, ...) { va_list args; dbus_bool_t retval; va_start (args, format); retval = _dbus_string_append_printf_valist (str, format, args); va_end (args); return retval; } /** * Appends block of bytes with the given length to a DBusString. * * @param str the DBusString * @param buffer the bytes to append * @param len the number of bytes to append * @returns #FALSE if not enough memory. */ dbus_bool_t _dbus_string_append_len (DBusString *str, const char *buffer, int len) { DBUS_STRING_PREAMBLE (str); _dbus_assert (buffer != NULL); _dbus_assert (len >= 0); return append (real, buffer, len); } /** * Appends a single byte to the string, returning #FALSE * if not enough memory. * * @param str the string * @param byte the byte to append * @returns #TRUE on success */ dbus_bool_t _dbus_string_append_byte (DBusString *str, unsigned char byte) { DBUS_STRING_PREAMBLE (str); if (!set_length (real, real->len + 1)) return FALSE; real->str[real->len-1] = byte; return TRUE; } static void delete (DBusRealString *real, int start, int len) { if (len == 0) return; memmove (real->str + start, real->str + start + len, real->len - (start + len)); real->len -= len; real->str[real->len] = '\0'; } /** * Deletes a segment of a DBusString with length len starting at * start. (Hint: to clear an entire string, setting length to 0 * with _dbus_string_set_length() is easier.) * * @param str the DBusString * @param start where to start deleting * @param len the number of bytes to delete */ void _dbus_string_delete (DBusString *str, int start, int len) { DBUS_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= real->len); _dbus_assert (len <= real->len - start); delete (real, start, len); } static dbus_bool_t copy (DBusRealString *source, int start, int len, DBusRealString *dest, int insert_at) { if (len == 0) return TRUE; if (!open_gap (len, dest, insert_at)) return FALSE; memmove (dest->str + insert_at, source->str + start, len); return TRUE; } /** * Checks assertions for two strings we're copying a segment between, * and declares real_source/real_dest variables. * * @param source the source string * @param start the starting offset * @param dest the dest string * @param insert_at where the copied segment is inserted */ #define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at) \ DBusRealString *real_source = (DBusRealString*) source; \ DBusRealString *real_dest = (DBusRealString*) dest; \ _dbus_assert ((source) != (dest)); \ DBUS_GENERIC_STRING_PREAMBLE (real_source); \ DBUS_GENERIC_STRING_PREAMBLE (real_dest); \ _dbus_assert (!real_dest->constant); \ _dbus_assert (!real_dest->locked); \ _dbus_assert ((start) >= 0); \ _dbus_assert ((start) <= real_source->len); \ _dbus_assert ((insert_at) >= 0); \ _dbus_assert ((insert_at) <= real_dest->len) /** * Moves the end of one string into another string. Both strings * must be initialized, valid strings. * * @param source the source string * @param start where to chop off the source string * @param dest the destination string * @param insert_at where to move the chopped-off part of source string * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_string_move (DBusString *source, int start, DBusString *dest, int insert_at) { DBusRealString *real_source = (DBusRealString*) source; _dbus_assert (start <= real_source->len); return _dbus_string_move_len (source, start, real_source->len - start, dest, insert_at); } /** * Like _dbus_string_move(), but does not delete the section * of the source string that's copied to the dest string. * * @param source the source string * @param start where to start copying the source string * @param dest the destination string * @param insert_at where to place the copied part of source string * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_string_copy (const DBusString *source, int start, DBusString *dest, int insert_at) { DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); return copy (real_source, start, real_source->len - start, real_dest, insert_at); } /** * Like _dbus_string_move(), but can move a segment from * the middle of the source string. * * @param source the source string * @param start first byte of source string to move * @param len length of segment to move * @param dest the destination string * @param insert_at where to move the bytes from the source string * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_string_move_len (DBusString *source, int start, int len, DBusString *dest, int insert_at) { DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); _dbus_assert (len >= 0); _dbus_assert ((start + len) <= real_source->len); if (len == 0) { return TRUE; } else if (start == 0 && len == real_source->len && real_dest->len == 0) { /* Short-circuit moving an entire existing string to an empty string * by just swapping the buffers. */ /* we assume ->constant doesn't matter as you can't have * a constant string involved in a move. */ #define ASSIGN_DATA(a, b) do { \ (a)->str = (b)->str; \ (a)->len = (b)->len; \ (a)->allocated = (b)->allocated; \ (a)->align_offset = (b)->align_offset; \ } while (0) DBusRealString tmp; ASSIGN_DATA (&tmp, real_source); ASSIGN_DATA (real_source, real_dest); ASSIGN_DATA (real_dest, &tmp); return TRUE; } else { if (!copy (real_source, start, len, real_dest, insert_at)) return FALSE; delete (real_source, start, len); return TRUE; } } /** * Like _dbus_string_copy(), but can copy a segment from the middle of * the source string. * * @param source the source string * @param start where to start copying the source string * @param len length of segment to copy * @param dest the destination string * @param insert_at where to place the copied segment of source string * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_string_copy_len (const DBusString *source, int start, int len, DBusString *dest, int insert_at) { DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); _dbus_assert (len >= 0); _dbus_assert (start <= real_source->len); _dbus_assert (len <= real_source->len - start); return copy (real_source, start, len, real_dest, insert_at); } /** * Replaces a segment of dest string with a segment of source string. * * @param source the source string * @param start where to start copying the source string * @param len length of segment to copy * @param dest the destination string * @param replace_at start of segment of dest string to replace * @param replace_len length of segment of dest string to replace * @returns #FALSE if not enough memory * */ dbus_bool_t _dbus_string_replace_len (const DBusString *source, int start, int len, DBusString *dest, int replace_at, int replace_len) { DBUS_STRING_COPY_PREAMBLE (source, start, dest, replace_at); _dbus_assert (len >= 0); _dbus_assert (start <= real_source->len); _dbus_assert (len <= real_source->len - start); _dbus_assert (replace_at >= 0); _dbus_assert (replace_at <= real_dest->len); _dbus_assert (replace_len <= real_dest->len - replace_at); if (len == replace_len) { memmove (real_dest->str + replace_at, real_source->str + start, len); } else if (len < replace_len) { memmove (real_dest->str + replace_at, real_source->str + start, len); delete (real_dest, replace_at + len, replace_len - len); } else { int diff; _dbus_assert (len > replace_len); diff = len - replace_len; /* First of all we check if destination string can be enlarged as * required, then we overwrite previous bytes */ if (!copy (real_source, start + replace_len, diff, real_dest, replace_at + replace_len)) return FALSE; memmove (real_dest->str + replace_at, real_source->str + start, replace_len); } return TRUE; } /** * Looks for the first occurance of a byte, deletes that byte, * and moves everything after the byte to the beginning of a * separate string. Both strings must be initialized, valid * strings. * * @param source the source string * @param byte the byte to remove and split the string at * @param tail the split off string * @returns #FALSE if not enough memory or if byte could not be found * */ dbus_bool_t _dbus_string_split_on_byte (DBusString *source, unsigned char byte, DBusString *tail) { int byte_position; char byte_string[2] = ""; int head_length; int tail_length; byte_string[0] = (char) byte; if (!_dbus_string_find (source, 0, byte_string, &byte_position)) return FALSE; head_length = byte_position; tail_length = _dbus_string_get_length (source) - head_length - 1; if (!_dbus_string_move_len (source, byte_position + 1, tail_length, tail, 0)) return FALSE; /* remove the trailing delimiter byte from the head now. */ if (!_dbus_string_set_length (source, head_length)) return FALSE; return TRUE; } /* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc * Pennington, and Tom Tromey are the authors and authorized relicense. */ /** computes length and mask of a unicode character * @param Char the char * @param Mask the mask variable to assign to * @param Len the length variable to assign to */ #define UTF8_COMPUTE(Char, Mask, Len) \ if (Char < 128) \ { \ Len = 1; \ Mask = 0x7f; \ } \ else if ((Char & 0xe0) == 0xc0) \ { \ Len = 2; \ Mask = 0x1f; \ } \ else if ((Char & 0xf0) == 0xe0) \ { \ Len = 3; \ Mask = 0x0f; \ } \ else if ((Char & 0xf8) == 0xf0) \ { \ Len = 4; \ Mask = 0x07; \ } \ else if ((Char & 0xfc) == 0xf8) \ { \ Len = 5; \ Mask = 0x03; \ } \ else if ((Char & 0xfe) == 0xfc) \ { \ Len = 6; \ Mask = 0x01; \ } \ else \ { \ Len = 0; \ Mask = 0; \ } /** * computes length of a unicode character in UTF-8 * @param Char the char */ #define UTF8_LENGTH(Char) \ ((Char) < 0x80 ? 1 : \ ((Char) < 0x800 ? 2 : \ ((Char) < 0x10000 ? 3 : \ ((Char) < 0x200000 ? 4 : \ ((Char) < 0x4000000 ? 5 : 6))))) /** * Gets a UTF-8 value. * * @param Result variable for extracted unicode char. * @param Chars the bytes to decode * @param Count counter variable * @param Mask mask for this char * @param Len length for this char in bytes */ #define UTF8_GET(Result, Chars, Count, Mask, Len) \ (Result) = (Chars)[0] & (Mask); \ for ((Count) = 1; (Count) < (Len); ++(Count)) \ { \ if (((Chars)[(Count)] & 0xc0) != 0x80) \ { \ (Result) = -1; \ break; \ } \ (Result) <<= 6; \ (Result) |= ((Chars)[(Count)] & 0x3f); \ } /** * Check whether a Unicode (5.2) char is in a valid range. * * The first check comes from the Unicode guarantee to never encode * a point above 0x0010ffff, since UTF-16 couldn't represent it. * * The second check covers surrogate pairs (category Cs). * * @param Char the character */ #define UNICODE_VALID(Char) \ ((Char) < 0x110000 && \ (((Char) & 0xFFFFF800) != 0xD800)) /** * Finds the given substring in the string, * returning #TRUE and filling in the byte index * where the substring was found, if it was found. * Returns #FALSE if the substring wasn't found. * Sets *start to the length of the string if the substring * is not found. * * @param str the string * @param start where to start looking * @param substr the substring * @param found return location for where it was found, or #NULL * @returns #TRUE if found */ dbus_bool_t _dbus_string_find (const DBusString *str, int start, const char *substr, int *found) { return _dbus_string_find_to (str, start, ((const DBusRealString*)str)->len, substr, found); } /** * Finds end of line ("\r\n" or "\n") in the string, * returning #TRUE and filling in the byte index * where the eol string was found, if it was found. * Returns #FALSE if eol wasn't found. * * @param str the string * @param start where to start looking * @param found return location for where eol was found or string length otherwise * @param found_len return length of found eol string or zero otherwise * @returns #TRUE if found */ dbus_bool_t _dbus_string_find_eol (const DBusString *str, int start, int *found, int *found_len) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); i = start; while (i < real->len) { if (real->str[i] == '\r') { if ((i+1) < real->len && real->str[i+1] == '\n') /* "\r\n" */ { if (found) *found = i; if (found_len) *found_len = 2; return TRUE; } else /* only "\r" */ { if (found) *found = i; if (found_len) *found_len = 1; return TRUE; } } else if (real->str[i] == '\n') /* only "\n" */ { if (found) *found = i; if (found_len) *found_len = 1; return TRUE; } ++i; } if (found) *found = real->len; if (found_len) *found_len = 0; return FALSE; } /** * Finds the given substring in the string, * up to a certain position, * returning #TRUE and filling in the byte index * where the substring was found, if it was found. * Returns #FALSE if the substring wasn't found. * Sets *start to the length of the string if the substring * is not found. * * @param str the string * @param start where to start looking * @param end where to stop looking * @param substr the substring * @param found return location for where it was found, or #NULL * @returns #TRUE if found */ dbus_bool_t _dbus_string_find_to (const DBusString *str, int start, int end, const char *substr, int *found) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (substr != NULL); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); _dbus_assert (substr != NULL); _dbus_assert (end <= real->len); _dbus_assert (start <= end); /* we always "find" an empty string */ if (*substr == '\0') { if (found) *found = start; return TRUE; } i = start; while (i < end) { if (real->str[i] == substr[0]) { int j = i + 1; while (j < end) { if (substr[j - i] == '\0') break; else if (real->str[j] != substr[j - i]) break; ++j; } if (substr[j - i] == '\0') { if (found) *found = i; return TRUE; } } ++i; } if (found) *found = end; return FALSE; } /** * Finds a blank (space or tab) in the string. Returns #TRUE * if found, #FALSE otherwise. If a blank is not found sets * *found to the length of the string. * * @param str the string * @param start byte index to start looking * @param found place to store the location of the first blank * @returns #TRUE if a blank was found */ dbus_bool_t _dbus_string_find_blank (const DBusString *str, int start, int *found) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); i = start; while (i < real->len) { if (real->str[i] == ' ' || real->str[i] == '\t') { if (found) *found = i; return TRUE; } ++i; } if (found) *found = real->len; return FALSE; } /** * Skips blanks from start, storing the first non-blank in *end * (blank is space or tab). * * @param str the string * @param start where to start * @param end where to store the first non-blank byte index */ void _dbus_string_skip_blank (const DBusString *str, int start, int *end) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); i = start; while (i < real->len) { if (!DBUS_IS_ASCII_BLANK (real->str[i])) break; ++i; } _dbus_assert (i == real->len || !DBUS_IS_ASCII_WHITE (real->str[i])); if (end) *end = i; } /** * Skips whitespace from start, storing the first non-whitespace in *end. * (whitespace is space, tab, newline, CR). * * @param str the string * @param start where to start * @param end where to store the first non-whitespace byte index */ void _dbus_string_skip_white (const DBusString *str, int start, int *end) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start <= real->len); _dbus_assert (start >= 0); i = start; while (i < real->len) { if (!DBUS_IS_ASCII_WHITE (real->str[i])) break; ++i; } _dbus_assert (i == real->len || !(DBUS_IS_ASCII_WHITE (real->str[i]))); if (end) *end = i; } /** * Skips whitespace from end, storing the start index of the trailing * whitespace in *start. (whitespace is space, tab, newline, CR). * * @param str the string * @param end where to start scanning backward * @param start where to store the start of whitespace chars */ void _dbus_string_skip_white_reverse (const DBusString *str, int end, int *start) { int i; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (end <= real->len); _dbus_assert (end >= 0); i = end; while (i > 0) { if (!DBUS_IS_ASCII_WHITE (real->str[i-1])) break; --i; } _dbus_assert (i >= 0 && (i == 0 || !(DBUS_IS_ASCII_WHITE (real->str[i-1])))); if (start) *start = i; } /** * Assigns a newline-terminated or \\r\\n-terminated line from the front * of the string to the given dest string. The dest string's previous * contents are deleted. If the source string contains no newline, * moves the entire source string to the dest string. * * @todo owen correctly notes that this is a stupid function (it was * written purely for test code, * e.g. dbus-message-builder.c). Probably should be enforced as test * code only with ifdef DBUS_ENABLE_EMBEDDED_TESTS * * @param source the source string * @param dest the destination string (contents are replaced) * @returns #FALSE if no memory, or source has length 0 */ dbus_bool_t _dbus_string_pop_line (DBusString *source, DBusString *dest) { int eol, eol_len; _dbus_string_set_length (dest, 0); eol = 0; eol_len = 0; if (!_dbus_string_find_eol (source, 0, &eol, &eol_len)) { _dbus_assert (eol == _dbus_string_get_length (source)); if (eol == 0) { /* If there's no newline and source has zero length, we're done */ return FALSE; } /* otherwise, the last line of the file has no eol characters */ } /* remember eol can be 0 if it's an empty line, but eol_len should not be zero also * since find_eol returned TRUE */ if (!_dbus_string_move_len (source, 0, eol + eol_len, dest, 0)) return FALSE; /* remove line ending */ if (!_dbus_string_set_length (dest, eol)) { _dbus_assert_not_reached ("out of memory when shortening a string"); return FALSE; } return TRUE; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Deletes up to and including the first blank space * in the string. * * @param str the string */ void _dbus_string_delete_first_word (DBusString *str) { int i; if (_dbus_string_find_blank (str, 0, &i)) _dbus_string_skip_blank (str, i, &i); _dbus_string_delete (str, 0, i); } #endif #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Deletes any leading blanks in the string * * @param str the string */ void _dbus_string_delete_leading_blanks (DBusString *str) { int i; _dbus_string_skip_blank (str, 0, &i); if (i > 0) _dbus_string_delete (str, 0, i); } #endif /** * Deletes leading and trailing whitespace * * @param str the string */ void _dbus_string_chop_white(DBusString *str) { int i; _dbus_string_skip_white (str, 0, &i); if (i > 0) _dbus_string_delete (str, 0, i); _dbus_string_skip_white_reverse (str, _dbus_string_get_length (str), &i); _dbus_string_set_length (str, i); } /** * Tests two DBusString for equality. * * @todo memcmp is probably faster * * @param a first string * @param b second string * @returns #TRUE if equal */ dbus_bool_t _dbus_string_equal (const DBusString *a, const DBusString *b) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; const DBusRealString *real_a = (const DBusRealString*) a; const DBusRealString *real_b = (const DBusRealString*) b; DBUS_GENERIC_STRING_PREAMBLE (real_a); DBUS_GENERIC_STRING_PREAMBLE (real_b); if (real_a->len != real_b->len) return FALSE; ap = real_a->str; bp = real_b->str; a_end = real_a->str + real_a->len; while (ap != a_end) { if (*ap != *bp) return FALSE; ++ap; ++bp; } return TRUE; } /** * Tests two DBusString for equality up to the given length. * The strings may be shorter than the given length. * * @todo write a unit test * * @todo memcmp is probably faster * * @param a first string * @param b second string * @param len the maximum length to look at * @returns #TRUE if equal for the given number of bytes */ dbus_bool_t _dbus_string_equal_len (const DBusString *a, const DBusString *b, int len) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; const DBusRealString *real_a = (const DBusRealString*) a; const DBusRealString *real_b = (const DBusRealString*) b; DBUS_GENERIC_STRING_PREAMBLE (real_a); DBUS_GENERIC_STRING_PREAMBLE (real_b); if (real_a->len != real_b->len && (real_a->len < len || real_b->len < len)) return FALSE; ap = real_a->str; bp = real_b->str; a_end = real_a->str + MIN (real_a->len, len); while (ap != a_end) { if (*ap != *bp) return FALSE; ++ap; ++bp; } return TRUE; } /** * Tests two sub-parts of two DBusString for equality. The specified * range of the first string must exist; the specified start position * of the second string must exist. * * @todo write a unit test * * @todo memcmp is probably faster * * @param a first string * @param a_start where to start substring in first string * @param a_len length of substring in first string * @param b second string * @param b_start where to start substring in second string * @returns #TRUE if the two substrings are equal */ dbus_bool_t _dbus_string_equal_substring (const DBusString *a, int a_start, int a_len, const DBusString *b, int b_start) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; const DBusRealString *real_a = (const DBusRealString*) a; const DBusRealString *real_b = (const DBusRealString*) b; DBUS_GENERIC_STRING_PREAMBLE (real_a); DBUS_GENERIC_STRING_PREAMBLE (real_b); _dbus_assert (a_start >= 0); _dbus_assert (a_len >= 0); _dbus_assert (a_start <= real_a->len); _dbus_assert (a_len <= real_a->len - a_start); _dbus_assert (b_start >= 0); _dbus_assert (b_start <= real_b->len); if (a_len > real_b->len - b_start) return FALSE; ap = real_a->str + a_start; bp = real_b->str + b_start; a_end = ap + a_len; while (ap != a_end) { if (*ap != *bp) return FALSE; ++ap; ++bp; } _dbus_assert (bp <= (real_b->str + real_b->len)); return TRUE; } /** * Checks whether a string is equal to a C string. * * @param a the string * @param c_str the C string * @returns #TRUE if equal */ dbus_bool_t _dbus_string_equal_c_str (const DBusString *a, const char *c_str) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; const DBusRealString *real_a = (const DBusRealString*) a; DBUS_GENERIC_STRING_PREAMBLE (real_a); _dbus_assert (c_str != NULL); ap = real_a->str; bp = (const unsigned char*) c_str; a_end = real_a->str + real_a->len; while (ap != a_end && *bp) { if (*ap != *bp) return FALSE; ++ap; ++bp; } if (ap != a_end || *bp) return FALSE; return TRUE; } /** * Checks whether a string starts with the given C string. * * @param a the string * @param c_str the C string * @returns #TRUE if string starts with it */ dbus_bool_t _dbus_string_starts_with_c_str (const DBusString *a, const char *c_str) { const unsigned char *ap; const unsigned char *bp; const unsigned char *a_end; const DBusRealString *real_a = (const DBusRealString*) a; DBUS_GENERIC_STRING_PREAMBLE (real_a); _dbus_assert (c_str != NULL); ap = real_a->str; bp = (const unsigned char*) c_str; a_end = real_a->str + real_a->len; while (ap != a_end && *bp) { if (*ap != *bp) return FALSE; ++ap; ++bp; } if (*bp == '\0') return TRUE; else return FALSE; } /** * Appends a two-character hex digit to a string, where the hex digit * has the value of the given byte. * * @param str the string * @param byte the byte * @returns #FALSE if no memory */ dbus_bool_t _dbus_string_append_byte_as_hex (DBusString *str, unsigned char byte) { const char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; if (!_dbus_string_append_byte (str, hexdigits[(byte >> 4)])) return FALSE; if (!_dbus_string_append_byte (str, hexdigits[(byte & 0x0f)])) { _dbus_string_set_length (str, _dbus_string_get_length (str) - 1); return FALSE; } return TRUE; } /** * Encodes a string in hex, the way MD5 and SHA-1 are usually * encoded. (Each byte is two hex digits.) * * @param source the string to encode * @param start byte index to start encoding * @param dest string where encoded data should be placed * @param insert_at where to place encoded data * @returns #TRUE if encoding was successful, #FALSE if no memory etc. */ dbus_bool_t _dbus_string_hex_encode (const DBusString *source, int start, DBusString *dest, int insert_at) { DBusString result; const unsigned char *p; const unsigned char *end; dbus_bool_t retval; _dbus_assert (start <= _dbus_string_get_length (source)); if (!_dbus_string_init (&result)) return FALSE; retval = FALSE; p = (const unsigned char*) _dbus_string_get_const_data (source); end = p + _dbus_string_get_length (source); p += start; while (p != end) { if (!_dbus_string_append_byte_as_hex (&result, *p)) goto out; ++p; } if (!_dbus_string_move (&result, 0, dest, insert_at)) goto out; retval = TRUE; out: _dbus_string_free (&result); return retval; } /** * Decodes a string from hex encoding. * * @param source the string to decode * @param start byte index to start decode * @param end_return return location of the end of the hex data, or #NULL * @param dest string where decoded data should be placed * @param insert_at where to place decoded data * @returns #TRUE if decoding was successful, #FALSE if no memory. */ dbus_bool_t _dbus_string_hex_decode (const DBusString *source, int start, int *end_return, DBusString *dest, int insert_at) { DBusString result; const unsigned char *p; const unsigned char *end; dbus_bool_t retval; dbus_bool_t high_bits; _dbus_assert (start <= _dbus_string_get_length (source)); if (!_dbus_string_init (&result)) return FALSE; retval = FALSE; high_bits = TRUE; p = (const unsigned char*) _dbus_string_get_const_data (source); end = p + _dbus_string_get_length (source); p += start; while (p != end) { unsigned int val; switch (*p) { case '0': val = 0; break; case '1': val = 1; break; case '2': val = 2; break; case '3': val = 3; break; case '4': val = 4; break; case '5': val = 5; break; case '6': val = 6; break; case '7': val = 7; break; case '8': val = 8; break; case '9': val = 9; break; case 'a': case 'A': val = 10; break; case 'b': case 'B': val = 11; break; case 'c': case 'C': val = 12; break; case 'd': case 'D': val = 13; break; case 'e': case 'E': val = 14; break; case 'f': case 'F': val = 15; break; default: goto done; } if (high_bits) { if (!_dbus_string_append_byte (&result, val << 4)) goto out; } else { int len; unsigned char b; len = _dbus_string_get_length (&result); b = _dbus_string_get_byte (&result, len - 1); b |= val; _dbus_string_set_byte (&result, len - 1, b); } high_bits = !high_bits; ++p; } done: if (!_dbus_string_move (&result, 0, dest, insert_at)) goto out; if (end_return) *end_return = p - (const unsigned char*) _dbus_string_get_const_data (source); retval = TRUE; out: _dbus_string_free (&result); return retval; } /** * Checks that the given range of the string is valid ASCII with no * nul bytes. If the given range is not entirely contained in the * string, returns #FALSE. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is all valid ASCII */ dbus_bool_t _dbus_string_validate_ascii (const DBusString *str, int start, int len) { const unsigned char *s; const unsigned char *end; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (start <= real->len); _dbus_assert (len >= 0); if (len > real->len - start) return FALSE; s = real->str + start; end = s + len; while (s != end) { if (_DBUS_UNLIKELY (!_DBUS_ISASCII (*s))) return FALSE; ++s; } return TRUE; } /** * Converts the given range of the string to lower case. * * @param str the string * @param start first byte index to convert * @param len number of bytes to convert */ void _dbus_string_tolower_ascii (const DBusString *str, int start, int len) { unsigned char *s; unsigned char *end; DBUS_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (start <= real->len); _dbus_assert (len >= 0); _dbus_assert (len <= real->len - start); s = real->str + start; end = s + len; while (s != end) { if (*s >= 'A' && *s <= 'Z') *s += 'a' - 'A'; ++s; } } /** * Converts the given range of the string to upper case. * * @param str the string * @param start first byte index to convert * @param len number of bytes to convert */ void _dbus_string_toupper_ascii (const DBusString *str, int start, int len) { unsigned char *s; unsigned char *end; DBUS_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (start <= real->len); _dbus_assert (len >= 0); _dbus_assert (len <= real->len - start); s = real->str + start; end = s + len; while (s != end) { if (*s >= 'a' && *s <= 'z') *s += 'A' - 'a'; ++s; } } /** * Checks that the given range of the string is valid UTF-8. If the * given range is not entirely contained in the string, returns * #FALSE. If the string contains any nul bytes in the given range, * returns #FALSE. If the start and start+len are not on character * boundaries, returns #FALSE. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is all valid UTF-8 */ dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str, int start, int len) { const unsigned char *p; const unsigned char *end; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (start <= real->len); _dbus_assert (len >= 0); /* we are doing _DBUS_UNLIKELY() here which might be * dubious in a generic library like GLib, but in D-Bus * we know we're validating messages and that it would * only be evil/broken apps that would have invalid * UTF-8. Also, this function seems to be a performance * bottleneck in profiles. */ if (_DBUS_UNLIKELY (len > real->len - start)) return FALSE; p = real->str + start; end = p + len; while (p < end) { int i, mask, char_len; dbus_unichar_t result; /* nul bytes considered invalid */ if (*p == '\0') break; /* Special-case ASCII; this makes us go a lot faster in * D-Bus profiles where we are typically validating * function names and such. We have to know that * all following checks will pass for ASCII though, * comments follow ... */ if (*p < 128) { ++p; continue; } UTF8_COMPUTE (*p, mask, char_len); if (_DBUS_UNLIKELY (char_len == 0)) /* ASCII: char_len == 1 */ break; /* check that the expected number of bytes exists in the remaining length */ if (_DBUS_UNLIKELY ((end - p) < char_len)) /* ASCII: p < end and char_len == 1 */ break; UTF8_GET (result, p, i, mask, char_len); /* Check for overlong UTF-8 */ if (_DBUS_UNLIKELY (UTF8_LENGTH (result) != char_len)) /* ASCII: UTF8_LENGTH == 1 */ break; #if 0 /* The UNICODE_VALID check below will catch this */ if (_DBUS_UNLIKELY (result == (dbus_unichar_t)-1)) /* ASCII: result = ascii value */ break; #endif if (_DBUS_UNLIKELY (!UNICODE_VALID (result))) /* ASCII: always valid */ break; /* UNICODE_VALID should have caught it */ _dbus_assert (result != (dbus_unichar_t)-1); p += char_len; } /* See that we covered the entire length if a length was * passed in */ if (_DBUS_UNLIKELY (p != end)) return FALSE; else return TRUE; } /** * Checks that the given range of the string is all nul bytes. If the * given range is not entirely contained in the string, returns * #FALSE. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is all nul bytes */ dbus_bool_t _dbus_string_validate_nul (const DBusString *str, int start, int len) { const unsigned char *s; const unsigned char *end; DBUS_CONST_STRING_PREAMBLE (str); _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= real->len); if (len > real->len - start) return FALSE; s = real->str + start; end = s + len; while (s != end) { if (_DBUS_UNLIKELY (*s != '\0')) return FALSE; ++s; } return TRUE; } /** * Clears all allocated bytes in the string to zero. * * @param str the string */ void _dbus_string_zero (DBusString *str) { DBUS_STRING_PREAMBLE (str); memset (real->str - real->align_offset, '\0', real->allocated); } /** @} */ /* tests are in dbus-string-util.c */ dbus-1.10.6/dbus/dbus-pipe.h0000644000175000017500000000450012602773110015532 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps.h Wrappers around system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_PIPE_H #define DBUS_PIPE_H #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include struct DBusPipe { int fd; }; DBUS_PRIVATE_EXPORT void _dbus_pipe_init (DBusPipe *pipe, int fd); DBUS_PRIVATE_EXPORT void _dbus_pipe_init_stdout (DBusPipe *pipe); DBUS_PRIVATE_EXPORT int _dbus_pipe_write (DBusPipe *pipe, const DBusString *buffer, int start, int len, DBusError *error); DBUS_PRIVATE_EXPORT int _dbus_pipe_close (DBusPipe *pipe, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_pipe_is_valid (DBusPipe *pipe); DBUS_PRIVATE_EXPORT void _dbus_pipe_invalidate (DBusPipe *pipe); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe); #endif dbus-1.10.6/dbus/dbus-pipe.c0000644000175000017500000000377712602773110015544 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pipe.c pipe implementation (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-pipe.h" /* * init a pipe instance. * * @param pipe the pipe * @param fd the file descriptor to init from */ void _dbus_pipe_init (DBusPipe *pipe, int fd) { pipe->fd = fd; } /** * init a pipe with stdout * * @param pipe the pipe */ void _dbus_pipe_init_stdout (DBusPipe *pipe) { _dbus_pipe_init (pipe, 1); } /** * check if a pipe is valid; pipes can be set invalid, similar to * a -1 file descriptor. * * @param pipe the pipe instance * @returns #FALSE if pipe is not valid */ dbus_bool_t _dbus_pipe_is_valid(DBusPipe *pipe) { return pipe->fd >= 0; } /** * Check if a pipe is stdout or stderr. * * @param pipe the pipe instance * @returns #TRUE if pipe is one of the standard out/err channels */ dbus_bool_t _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe) { return pipe->fd == 1 || pipe->fd == 2; } /** * Initializes a pipe to an invalid value. * @param pipe the pipe */ void _dbus_pipe_invalidate (DBusPipe *pipe) { pipe->fd = -1; } dbus-1.10.6/dbus/dbus-mempool.h0000644000175000017500000000355712602773110016260 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-mempool.h Memory pools * * Copyright (C) 2002 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MEMPOOL_H #define DBUS_MEMPOOL_H #include #include #include DBUS_BEGIN_DECLS typedef struct DBusMemPool DBusMemPool; DBUS_PRIVATE_EXPORT DBusMemPool* _dbus_mem_pool_new (int element_size, dbus_bool_t zero_elements); DBUS_PRIVATE_EXPORT void _dbus_mem_pool_free (DBusMemPool *pool); DBUS_PRIVATE_EXPORT void* _dbus_mem_pool_alloc (DBusMemPool *pool); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_mem_pool_dealloc (DBusMemPool *pool, void *element); /* if DBUS_ENABLE_STATS */ void _dbus_mem_pool_get_stats (DBusMemPool *pool, dbus_uint32_t *in_use_p, dbus_uint32_t *in_free_list_p, dbus_uint32_t *allocated_p); DBUS_END_DECLS #endif /* DBUS_MEMPOOL_H */ dbus-1.10.6/dbus/dbus-mempool.c0000644000175000017500000004014212602773110016242 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-mempool.h Memory pools * * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-mempool.h" #include "dbus-internals.h" #include "dbus-valgrind-internal.h" /** * @defgroup DBusMemPool memory pools * @ingroup DBusInternals * @brief DBusMemPool object * * Types and functions related to DBusMemPool. A memory pool is used * to decrease memory fragmentation/overhead and increase speed for * blocks of small uniformly-sized objects. The main point is to avoid * the overhead of a malloc block for each small object, speed is * secondary. */ /** * @defgroup DBusMemPoolInternals Memory pool implementation details * @ingroup DBusInternals * @brief DBusMemPool implementation details * * The guts of DBusMemPool. * * @{ */ /** * typedef so DBusFreedElement struct can refer to itself. */ typedef struct DBusFreedElement DBusFreedElement; /** * struct representing an element on the free list. * We just cast freed elements to this so we can * make a list out of them. */ struct DBusFreedElement { DBusFreedElement *next; /**< next element of the free list */ }; /** * The dummy size of the variable-length "elements" * field in DBusMemBlock */ #define ELEMENT_PADDING 4 /** * Typedef for DBusMemBlock so the struct can recursively * point to itself. */ typedef struct DBusMemBlock DBusMemBlock; /** * DBusMemBlock object represents a single malloc()-returned * block that gets chunked up into objects in the memory pool. */ struct DBusMemBlock { DBusMemBlock *next; /**< next block in the list, which is already used up; * only saved so we can free all the blocks * when we free the mem pool. */ /* this is a long so that "elements" is aligned */ long used_so_far; /**< bytes of this block already allocated as elements. */ unsigned char elements[ELEMENT_PADDING]; /**< the block data, actually allocated to required size */ }; /** * Internals fields of DBusMemPool */ struct DBusMemPool { int element_size; /**< size of a single object in the pool */ int block_size; /**< size of most recently allocated block */ unsigned int zero_elements : 1; /**< whether to zero-init allocated elements */ DBusFreedElement *free_elements; /**< a free list of elements to recycle */ DBusMemBlock *blocks; /**< blocks of memory from malloc() */ int allocated_elements; /**< Count of outstanding allocated elements */ }; /** @} */ /** * @addtogroup DBusMemPool * * @{ */ /** * @typedef DBusMemPool * * Opaque object representing a memory pool. Memory pools allow * avoiding per-malloc-block memory overhead when allocating a lot of * small objects that are all the same size. They are slightly * faster than calling malloc() also. */ /** * Creates a new memory pool, or returns #NULL on failure. Objects in * the pool must be at least sizeof(void*) bytes each, due to the way * memory pools work. To avoid creating 64 bit problems, this means at * least 8 bytes on all platforms, unless you are 4 bytes on 32-bit * and 8 bytes on 64-bit. * * @param element_size size of an element allocated from the pool. * @param zero_elements whether to zero-initialize elements * @returns the new pool or #NULL */ DBusMemPool* _dbus_mem_pool_new (int element_size, dbus_bool_t zero_elements) { DBusMemPool *pool; pool = dbus_new0 (DBusMemPool, 1); if (pool == NULL) return NULL; /* Make the element size at least 8 bytes. */ if (element_size < 8) element_size = 8; /* these assertions are equivalent but the first is more clear * to programmers that see it fail. */ _dbus_assert (element_size >= (int) sizeof (void*)); _dbus_assert (element_size >= (int) sizeof (DBusFreedElement)); /* align the element size to a pointer boundary so we won't get bus * errors under other architectures. */ pool->element_size = _DBUS_ALIGN_VALUE (element_size, sizeof (void *)); pool->zero_elements = zero_elements != FALSE; pool->allocated_elements = 0; /* pick a size for the first block; it increases * for each block we need to allocate. This is * actually half the initial block size * since _dbus_mem_pool_alloc() unconditionally * doubles it prior to creating a new block. */ pool->block_size = pool->element_size * 8; _dbus_assert ((pool->block_size % pool->element_size) == 0); VALGRIND_CREATE_MEMPOOL (pool, 0, zero_elements); return pool; } /** * Frees a memory pool (and all elements allocated from it). * * @param pool the memory pool. */ void _dbus_mem_pool_free (DBusMemPool *pool) { DBusMemBlock *block; VALGRIND_DESTROY_MEMPOOL (pool); block = pool->blocks; while (block != NULL) { DBusMemBlock *next = block->next; dbus_free (block); block = next; } dbus_free (pool); } /** * Allocates an object from the memory pool. * The object must be freed with _dbus_mem_pool_dealloc(). * * @param pool the memory pool * @returns the allocated object or #NULL if no memory. */ void* _dbus_mem_pool_alloc (DBusMemPool *pool) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (_dbus_disable_mem_pools ()) { DBusMemBlock *block; int alloc_size; /* This is obviously really silly, but it's * debug-mode-only code that is compiled out * when tests are disabled (_dbus_disable_mem_pools() * is a constant expression FALSE so this block * should vanish) */ alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->element_size; if (pool->zero_elements) block = dbus_malloc0 (alloc_size); else block = dbus_malloc (alloc_size); if (block != NULL) { block->next = pool->blocks; pool->blocks = block; pool->allocated_elements += 1; VALGRIND_MEMPOOL_ALLOC (pool, (void *) &block->elements[0], pool->element_size); return (void*) &block->elements[0]; } else return NULL; } else #endif { if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING mempool alloc\n"); return NULL; } else if (pool->free_elements) { DBusFreedElement *element = pool->free_elements; pool->free_elements = pool->free_elements->next; VALGRIND_MEMPOOL_ALLOC (pool, element, pool->element_size); if (pool->zero_elements) memset (element, '\0', pool->element_size); pool->allocated_elements += 1; return element; } else { void *element; if (pool->blocks == NULL || pool->blocks->used_so_far == pool->block_size) { /* Need a new block */ DBusMemBlock *block; int alloc_size; #ifdef DBUS_ENABLE_EMBEDDED_TESTS int saved_counter; #endif if (pool->block_size <= _DBUS_INT_MAX / 4) /* avoid overflow */ { /* use a larger block size for our next block */ pool->block_size *= 2; _dbus_assert ((pool->block_size % pool->element_size) == 0); } alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->block_size; #ifdef DBUS_ENABLE_EMBEDDED_TESTS /* We save/restore the counter, so that memory pools won't * cause a given function to have different number of * allocations on different invocations. i.e. when testing * we want consistent alloc patterns. So we skip our * malloc here for purposes of failed alloc simulation. */ saved_counter = _dbus_get_fail_alloc_counter (); _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); #endif if (pool->zero_elements) block = dbus_malloc0 (alloc_size); else block = dbus_malloc (alloc_size); #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_set_fail_alloc_counter (saved_counter); _dbus_assert (saved_counter == _dbus_get_fail_alloc_counter ()); #endif if (block == NULL) return NULL; block->used_so_far = 0; block->next = pool->blocks; pool->blocks = block; } element = &pool->blocks->elements[pool->blocks->used_so_far]; pool->blocks->used_so_far += pool->element_size; pool->allocated_elements += 1; VALGRIND_MEMPOOL_ALLOC (pool, element, pool->element_size); return element; } } } /** * Deallocates an object previously created with * _dbus_mem_pool_alloc(). The previous object * must have come from this same pool. * @param pool the memory pool * @param element the element earlier allocated. * @returns #TRUE if there are no remaining allocated elements */ dbus_bool_t _dbus_mem_pool_dealloc (DBusMemPool *pool, void *element) { VALGRIND_MEMPOOL_FREE (pool, element); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (_dbus_disable_mem_pools ()) { DBusMemBlock *block; DBusMemBlock *prev; /* mmm, fast. ;-) debug-only code, so doesn't matter. */ prev = NULL; block = pool->blocks; while (block != NULL) { if (block->elements == (unsigned char*) element) { if (prev) prev->next = block->next; else pool->blocks = block->next; dbus_free (block); _dbus_assert (pool->allocated_elements > 0); pool->allocated_elements -= 1; if (pool->allocated_elements == 0) _dbus_assert (pool->blocks == NULL); return pool->blocks == NULL; } prev = block; block = block->next; } _dbus_assert_not_reached ("freed nonexistent block"); return FALSE; } else #endif { DBusFreedElement *freed; freed = element; /* used for internal mempool administration */ VALGRIND_MAKE_MEM_UNDEFINED (freed, sizeof (*freed)); freed->next = pool->free_elements; pool->free_elements = freed; _dbus_assert (pool->allocated_elements > 0); pool->allocated_elements -= 1; return pool->allocated_elements == 0; } } #ifdef DBUS_ENABLE_STATS void _dbus_mem_pool_get_stats (DBusMemPool *pool, dbus_uint32_t *in_use_p, dbus_uint32_t *in_free_list_p, dbus_uint32_t *allocated_p) { DBusMemBlock *block; DBusFreedElement *freed; dbus_uint32_t in_use = 0; dbus_uint32_t in_free_list = 0; dbus_uint32_t allocated = 0; if (pool != NULL) { in_use = pool->element_size * pool->allocated_elements; for (freed = pool->free_elements; freed != NULL; freed = freed->next) { in_free_list += pool->element_size; } for (block = pool->blocks; block != NULL; block = block->next) { if (block == pool->blocks) allocated += pool->block_size; else allocated += block->used_so_far; } } if (in_use_p != NULL) *in_use_p = in_use; if (in_free_list_p != NULL) *in_free_list_p = in_free_list; if (allocated_p != NULL) *allocated_p = allocated; } #endif /* DBUS_ENABLE_STATS */ /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include #include static void time_for_size (int size) { int i; int j; #ifdef DBUS_ENABLE_VERBOSE_MODE clock_t start; clock_t end; #endif #define FREE_ARRAY_SIZE 512 #define N_ITERATIONS FREE_ARRAY_SIZE * 512 void *to_free[FREE_ARRAY_SIZE]; DBusMemPool *pool; _dbus_verbose ("Timings for size %d\n", size); _dbus_verbose (" malloc\n"); #ifdef DBUS_ENABLE_VERBOSE_MODE start = clock (); #endif i = 0; j = 0; while (i < N_ITERATIONS) { to_free[j] = dbus_malloc (size); _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ ++j; if (j == FREE_ARRAY_SIZE) { j = 0; while (j < FREE_ARRAY_SIZE) { dbus_free (to_free[j]); ++j; } j = 0; } ++i; } #ifdef DBUS_ENABLE_VERBOSE_MODE end = clock (); _dbus_verbose (" created/destroyed %d elements in %g seconds\n", N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); _dbus_verbose (" mempools\n"); start = clock (); #endif pool = _dbus_mem_pool_new (size, FALSE); i = 0; j = 0; while (i < N_ITERATIONS) { to_free[j] = _dbus_mem_pool_alloc (pool); _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ ++j; if (j == FREE_ARRAY_SIZE) { j = 0; while (j < FREE_ARRAY_SIZE) { _dbus_mem_pool_dealloc (pool, to_free[j]); ++j; } j = 0; } ++i; } _dbus_mem_pool_free (pool); #ifdef DBUS_ENABLE_VERBOSE_MODE end = clock (); _dbus_verbose (" created/destroyed %d elements in %g seconds\n", N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); _dbus_verbose (" zeroed malloc\n"); start = clock (); #endif i = 0; j = 0; while (i < N_ITERATIONS) { to_free[j] = dbus_malloc0 (size); _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ ++j; if (j == FREE_ARRAY_SIZE) { j = 0; while (j < FREE_ARRAY_SIZE) { dbus_free (to_free[j]); ++j; } j = 0; } ++i; } #ifdef DBUS_ENABLE_VERBOSE_MODE end = clock (); _dbus_verbose (" created/destroyed %d elements in %g seconds\n", N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); _dbus_verbose (" zeroed mempools\n"); start = clock (); #endif pool = _dbus_mem_pool_new (size, TRUE); i = 0; j = 0; while (i < N_ITERATIONS) { to_free[j] = _dbus_mem_pool_alloc (pool); _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ ++j; if (j == FREE_ARRAY_SIZE) { j = 0; while (j < FREE_ARRAY_SIZE) { _dbus_mem_pool_dealloc (pool, to_free[j]); ++j; } j = 0; } ++i; } _dbus_mem_pool_free (pool); #ifdef DBUS_ENABLE_VERBOSE_MODE end = clock (); _dbus_verbose (" created/destroyed %d elements in %g seconds\n", N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); #endif } /** * @ingroup DBusMemPoolInternals * Unit test for DBusMemPool * @returns #TRUE on success. */ dbus_bool_t _dbus_mem_pool_test (void) { int i; int element_sizes[] = { 4, 8, 16, 50, 124 }; i = 0; while (i < _DBUS_N_ELEMENTS (element_sizes)) { time_for_size (element_sizes[i]); ++i; } return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-memory.c0000644000175000017500000005714112602773110016111 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-memory.c D-Bus memory handling * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-memory.h" #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-list.h" #include "dbus-threads.h" #include /** * @defgroup DBusMemory Memory Allocation * @ingroup DBus * @brief dbus_malloc(), dbus_free(), etc. * * Functions and macros related to allocating and releasing * blocks of memory. * */ /** * @defgroup DBusMemoryInternals Memory allocation implementation details * @ingroup DBusInternals * @brief internals of dbus_malloc() etc. * * Implementation details related to allocating and releasing blocks * of memory. */ /** * @addtogroup DBusMemory * * @{ */ /** * @def dbus_new * * Safe macro for using dbus_malloc(). Accepts the type * to allocate and the number of type instances to * allocate as arguments, and returns a memory block * cast to the desired type, instead of as a void*. * * @param type type name to allocate * @param count number of instances in the allocated array * @returns the new memory block or #NULL on failure */ /** * @def dbus_new0 * * Safe macro for using dbus_malloc0(). Accepts the type * to allocate and the number of type instances to * allocate as arguments, and returns a memory block * cast to the desired type, instead of as a void*. * The allocated array is initialized to all-bits-zero. * * @param type type name to allocate * @param count number of instances in the allocated array * @returns the new memory block or #NULL on failure */ /** * @typedef DBusFreeFunction * * The type of a function which frees a block of memory. * * @param memory the memory to free */ /** @} */ /* end of public API docs */ /** * @addtogroup DBusMemoryInternals * * @{ */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS static dbus_bool_t debug_initialized = FALSE; static int fail_nth = -1; static size_t fail_size = 0; static int fail_alloc_counter = _DBUS_INT_MAX; static int n_failures_per_failure = 1; static int n_failures_this_failure = 0; static dbus_bool_t guards = FALSE; static dbus_bool_t disable_mem_pools = FALSE; static dbus_bool_t backtrace_on_fail_alloc = FALSE; static dbus_bool_t malloc_cannot_fail = FALSE; static DBusAtomic n_blocks_outstanding = {0}; /** value stored in guard padding for debugging buffer overrun */ #define GUARD_VALUE 0xdeadbeef /** size of the information about the block stored in guard mode */ #define GUARD_INFO_SIZE 8 /** size of the GUARD_VALUE-filled padding after the header info */ #define GUARD_START_PAD 16 /** size of the GUARD_VALUE-filled padding at the end of the block */ #define GUARD_END_PAD 16 /** size of stuff at start of block */ #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE) /** total extra size over the requested allocation for guard stuff */ #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD) static void _dbus_initialize_malloc_debug (void) { if (!debug_initialized) { debug_initialized = TRUE; if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL) { fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH")); fail_alloc_counter = fail_nth; _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth); } if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL) { fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN")); _dbus_verbose ("Will fail mallocs over %ld bytes\n", (long) fail_size); } if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL) { guards = TRUE; _dbus_verbose ("Will use dbus_malloc guards\n"); } if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL) { disable_mem_pools = TRUE; _dbus_verbose ("Will disable memory pools\n"); } if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL) { backtrace_on_fail_alloc = TRUE; _dbus_verbose ("Will backtrace on failing a dbus_malloc\n"); } if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL) { malloc_cannot_fail = TRUE; _dbus_verbose ("Will abort if system malloc() and friends fail\n"); } } } /** * Whether to turn off mem pools, useful for leak checking. * * @returns #TRUE if mempools should not be used. */ dbus_bool_t _dbus_disable_mem_pools (void) { _dbus_initialize_malloc_debug (); return disable_mem_pools; } /** * Sets the number of allocations until we simulate a failed * allocation. If set to 0, the next allocation to run * fails; if set to 1, one succeeds then the next fails; etc. * Set to _DBUS_INT_MAX to not fail anything. * * @param until_next_fail number of successful allocs before one fails */ void _dbus_set_fail_alloc_counter (int until_next_fail) { _dbus_initialize_malloc_debug (); fail_alloc_counter = until_next_fail; #if 0 _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter); #endif } /** * Gets the number of successful allocs until we'll simulate * a failed alloc. * * @returns current counter value */ int _dbus_get_fail_alloc_counter (void) { _dbus_initialize_malloc_debug (); return fail_alloc_counter; } /** * Sets how many mallocs to fail when the fail alloc counter reaches * 0. * * @param failures_per_failure number to fail */ void _dbus_set_fail_alloc_failures (int failures_per_failure) { n_failures_per_failure = failures_per_failure; } /** * Gets the number of failures we'll have when the fail malloc * counter reaches 0. * * @returns number of failures planned */ int _dbus_get_fail_alloc_failures (void) { return n_failures_per_failure; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Called when about to alloc some memory; if * it returns #TRUE, then the allocation should * fail. If it returns #FALSE, then the allocation * should not fail. * * @returns #TRUE if this alloc should fail */ dbus_bool_t _dbus_decrement_fail_alloc_counter (void) { _dbus_initialize_malloc_debug (); #ifdef DBUS_WIN_FIXME { static dbus_bool_t called = 0; if (!called) { _dbus_verbose("TODO: memory allocation testing errors disabled for now\n"); called = 1; } return FALSE; } #endif if (fail_alloc_counter <= 0) { if (backtrace_on_fail_alloc) _dbus_print_backtrace (); _dbus_verbose ("failure %d\n", n_failures_this_failure); n_failures_this_failure += 1; if (n_failures_this_failure >= n_failures_per_failure) { if (fail_nth >= 0) fail_alloc_counter = fail_nth; else fail_alloc_counter = _DBUS_INT_MAX; n_failures_this_failure = 0; _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter); } return TRUE; } else { fail_alloc_counter -= 1; return FALSE; } } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** * Get the number of outstanding malloc()'d blocks. * * @returns number of blocks */ int _dbus_get_malloc_blocks_outstanding (void) { return _dbus_atomic_get (&n_blocks_outstanding); } /** * Where the block came from. */ typedef enum { SOURCE_UNKNOWN, SOURCE_MALLOC, SOURCE_REALLOC, SOURCE_MALLOC_ZERO, SOURCE_REALLOC_NULL } BlockSource; static const char* source_string (BlockSource source) { switch (source) { case SOURCE_UNKNOWN: return "unknown"; case SOURCE_MALLOC: return "malloc"; case SOURCE_REALLOC: return "realloc"; case SOURCE_MALLOC_ZERO: return "malloc0"; case SOURCE_REALLOC_NULL: return "realloc(NULL)"; } _dbus_assert_not_reached ("Invalid malloc block source ID"); return "invalid!"; } static void check_guards (void *free_block, dbus_bool_t overwrite) { if (free_block != NULL) { unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET; size_t requested_bytes = *(dbus_uint32_t*)block; BlockSource source = *(dbus_uint32_t*)(block + 4); unsigned int i; dbus_bool_t failed; failed = FALSE; #if 0 _dbus_verbose ("Checking %d bytes request from source %s\n", requested_bytes, source_string (source)); #endif i = GUARD_INFO_SIZE; while (i < GUARD_START_OFFSET) { dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; if (value != GUARD_VALUE) { _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n", (long) requested_bytes, source_string (source), value, i, GUARD_VALUE); failed = TRUE; } i += 4; } i = GUARD_START_OFFSET + requested_bytes; while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) { dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; if (value != GUARD_VALUE) { _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n", (long) requested_bytes, source_string (source), value, i, GUARD_VALUE); failed = TRUE; } i += 4; } /* set memory to anything but nul bytes */ if (overwrite) memset (free_block, 'g', requested_bytes); if (failed) _dbus_assert_not_reached ("guard value corruption"); } } static void* set_guards (void *real_block, size_t requested_bytes, BlockSource source) { unsigned char *block = real_block; unsigned int i; if (block == NULL) return NULL; _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE); *((dbus_uint32_t*)block) = requested_bytes; *((dbus_uint32_t*)(block + 4)) = source; i = GUARD_INFO_SIZE; while (i < GUARD_START_OFFSET) { (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; i += 4; } i = GUARD_START_OFFSET + requested_bytes; while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) { (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; i += 4; } check_guards (block + GUARD_START_OFFSET, FALSE); return block + GUARD_START_OFFSET; } #endif /** @} */ /* End of internals docs */ /** * @addtogroup DBusMemory * * @{ */ /** * Allocates the given number of bytes, as with standard * malloc(). Guaranteed to return #NULL if bytes is zero * on all platforms. Returns #NULL if the allocation fails. * The memory must be released with dbus_free(). * * dbus_malloc() memory is NOT safe to free with regular free() from * the C library. Free it with dbus_free() only. * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc (size_t bytes) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* some system mallocs handle this, some don't */ return NULL; #ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld + %ld)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_MALLOC); } #endif else { void *mem; mem = malloc (bytes); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); _dbus_abort (); } #endif return mem; } } /** * Allocates the given number of bytes, as with standard malloc(), but * all bytes are initialized to zero as with calloc(). Guaranteed to * return #NULL if bytes is zero on all platforms. Returns #NULL if the * allocation fails. The memory must be released with dbus_free(). * * dbus_malloc0() memory is NOT safe to free with regular free() from * the C library. Free it with dbus_free() only. * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc0 (size_t bytes) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) return NULL; #ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { void *block; block = calloc (bytes + GUARD_EXTRA_SIZE, 1); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_MALLOC_ZERO); } #endif else { void *mem; mem = calloc (bytes, 1); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes); _dbus_abort (); } #endif return mem; } } /** * Resizes a block of memory previously allocated by dbus_malloc() or * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes * is zero on all platforms. Returns #NULL if the resize fails. * If the resize fails, the memory is not freed. * * @param memory block to be resized * @param bytes new size of the memory block * @return allocated memory, or #NULL if the resize fails. */ void* dbus_realloc (void *memory, size_t bytes) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes); return NULL; } #endif if (bytes == 0) /* guarantee this is safe */ { dbus_free (memory); return NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) { if (memory) { size_t old_bytes; void *block; check_guards (memory, FALSE); block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); if (block == NULL) { if (malloc_cannot_fail) { _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n", memory, (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return NULL; } old_bytes = *(dbus_uint32_t*)block; if (bytes >= old_bytes) /* old guards shouldn't have moved */ check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); return set_guards (block, bytes, SOURCE_REALLOC); } else { void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) { _dbus_atomic_inc (&n_blocks_outstanding); } else if (malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld + %ld)\n", (long) bytes, (long) GUARD_EXTRA_SIZE); _dbus_abort (); } return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } #endif else { void *mem; mem = realloc (memory, bytes); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem == NULL && malloc_cannot_fail) { _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); _dbus_abort (); } if (memory == NULL && mem != NULL) _dbus_atomic_inc (&n_blocks_outstanding); #endif return mem; } } /** * Frees a block of memory previously allocated by dbus_malloc() or * dbus_malloc0(). If passed #NULL, does nothing. * * @param memory block to be freed */ void dbus_free (void *memory) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (guards) { check_guards (memory, TRUE); if (memory) { #ifdef DBUS_DISABLE_ASSERT _dbus_atomic_dec (&n_blocks_outstanding); #else dbus_int32_t old_value; old_value = _dbus_atomic_dec (&n_blocks_outstanding); _dbus_assert (old_value >= 1); #endif free (((unsigned char*)memory) - GUARD_START_OFFSET); } return; } #endif if (memory) /* we guarantee it's safe to free (NULL) */ { #ifdef DBUS_ENABLE_EMBEDDED_TESTS #ifdef DBUS_DISABLE_ASSERT _dbus_atomic_dec (&n_blocks_outstanding); #else dbus_int32_t old_value; old_value = _dbus_atomic_dec (&n_blocks_outstanding); _dbus_assert (old_value >= 1); #endif #endif free (memory); } } /** * Frees a #NULL-terminated array of strings. * If passed #NULL, does nothing. * * @param str_array the array to be freed */ void dbus_free_string_array (char **str_array) { if (str_array) { int i; i = 0; while (str_array[i]) { dbus_free (str_array[i]); i++; } dbus_free (str_array); } } /** @} */ /* End of public API docs block */ /** * @addtogroup DBusMemoryInternals * * @{ */ /** * _dbus_current_generation is used to track each * time that dbus_shutdown() is called, so we can * reinit things after it's been called. It is simply * incremented each time we shut down. */ int _dbus_current_generation = 1; /** * Represents a function to be called on shutdown. */ typedef struct ShutdownClosure ShutdownClosure; /** * This struct represents a function to be called on shutdown. */ struct ShutdownClosure { ShutdownClosure *next; /**< Next ShutdownClosure */ DBusShutdownFunction func; /**< Function to call */ void *data; /**< Data for function */ }; /* Protected by _DBUS_LOCK (shutdown_funcs) */ static ShutdownClosure *registered_globals = NULL; /** * Register a cleanup function to be called exactly once * the next time dbus_shutdown() is called. * * @param func the function * @param data data to pass to the function * @returns #FALSE on not enough memory */ dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction func, void *data) { dbus_bool_t ok; if (!_DBUS_LOCK (shutdown_funcs)) return FALSE; ok = _dbus_register_shutdown_func_unlocked (func, data); _DBUS_UNLOCK (shutdown_funcs); return ok; } dbus_bool_t _dbus_register_shutdown_func_unlocked (DBusShutdownFunction func, void *data) { ShutdownClosure *c; c = dbus_new (ShutdownClosure, 1); if (c == NULL) return FALSE; c->func = func; c->data = data; c->next = registered_globals; registered_globals = c; return TRUE; } /** @} */ /* End of private API docs block */ /** * @addtogroup DBusMemory * * @{ */ /** * Frees all memory allocated internally by libdbus and * reverses the effects of dbus_threads_init(). libdbus keeps internal * global variables, for example caches and thread locks, and it * can be useful to free these internal data structures. * * dbus_shutdown() does NOT free memory that was returned * to the application. It only frees libdbus-internal * data structures. * * You MUST free all memory and release all reference counts * returned to you by libdbus prior to calling dbus_shutdown(). * * If a shared connection is open, calling dbus_shutdown() will * drain its queue of messages and disconnect it. In particular, * this will result in processing of the special Disconnected * signal, which may result in a call to _exit(), unless you * have used dbus_connection_set_exit_on_disconnect() to disable * that behaviour. * * You can't continue to use any D-Bus objects, such as connections, * that were allocated prior to dbus_shutdown(). You can, however, * start over; call dbus_threads_init() again, create new connections, * and so forth. * * WARNING: dbus_shutdown() is NOT thread safe, it must be called * while NO other threads are using D-Bus. (Remember, you have to free * all D-Bus objects and memory before you call dbus_shutdown(), so no * thread can be using libdbus.) * * The purpose of dbus_shutdown() is to allow applications to get * clean output from memory leak checkers. dbus_shutdown() may also be * useful if you want to dlopen() libdbus instead of linking to it, * and want to be able to unload the library again. * * There is absolutely no requirement to call dbus_shutdown() - in fact, * most applications won't bother and should not feel guilty. * * You have to know that nobody is using libdbus in your application's * process before you can call dbus_shutdown(). One implication of this * is that calling dbus_shutdown() from a library is almost certainly * wrong, since you don't know what the rest of the app is up to. * */ void dbus_shutdown (void) { while (registered_globals != NULL) { ShutdownClosure *c; c = registered_globals; registered_globals = c->next; (* c->func) (c->data); dbus_free (c); } /* We wrap this in the thread-initialization lock because * dbus_threads_init() uses the current generation to tell whether * we're initialized, so we need to make sure that un-initializing * propagates into all threads. */ _dbus_threads_lock_platform_specific (); _dbus_current_generation += 1; _dbus_threads_unlock_platform_specific (); } /** @} */ /** End of public API docs block */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" /** * @ingroup DBusMemoryInternals * Unit test for DBusMemory * @returns #TRUE on success. */ dbus_bool_t _dbus_memory_test (void) { dbus_bool_t old_guards; void *p; size_t size; old_guards = guards; guards = TRUE; p = dbus_malloc (4); if (p == NULL) _dbus_assert_not_reached ("no memory"); for (size = 4; size < 256; size += 4) { p = dbus_realloc (p, size); if (p == NULL) _dbus_assert_not_reached ("no memory"); } for (size = 256; size != 0; size -= 4) { p = dbus_realloc (p, size); if (p == NULL) _dbus_assert_not_reached ("no memory"); } dbus_free (p); guards = old_guards; return TRUE; } #endif dbus-1.10.6/dbus/dbus-marshal-basic.h0000644000175000017500000002707212602773110017314 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-basic.h Marshalling routines for basic (primitive) types * * Copyright (C) 2002 CodeFactory AB * Copyright (C) 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MARSHAL_BASIC_H #define DBUS_MARSHAL_BASIC_H #ifdef HAVE_BYTESWAP_H #include #endif #include #include #include #include #ifdef WORDS_BIGENDIAN #define DBUS_COMPILER_BYTE_ORDER DBUS_BIG_ENDIAN #else #define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN #endif #ifdef HAVE_BYTESWAP_H #define DBUS_UINT16_SWAP_LE_BE_CONSTANT(val) bswap_16(val) #define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) bswap_32(val) #else /* HAVE_BYTESWAP_H */ #define DBUS_UINT16_SWAP_LE_BE_CONSTANT(val) ((dbus_uint16_t) ( \ (dbus_uint16_t) ((dbus_uint16_t) (val) >> 8) | \ (dbus_uint16_t) ((dbus_uint16_t) (val) << 8))) #define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) ((dbus_uint32_t) ( \ (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) | \ (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) << 8) | \ (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >> 8) | \ (((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24))) #endif /* HAVE_BYTESWAP_H */ #ifdef HAVE_BYTESWAP_H #define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val) bswap_64(val) #else /* HAVE_BYTESWAP_H */ #define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val) ((dbus_uint64_t) ( \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000000000ff)) << 56) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000000000ff00)) << 40) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000000000ff0000)) << 24) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000ff000000)) << 8) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000ff00000000)) >> 8) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000ff0000000000)) >> 24) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00ff000000000000)) >> 40) | \ (((dbus_uint64_t) (val) & \ (dbus_uint64_t) DBUS_UINT64_CONSTANT (0xff00000000000000)) >> 56))) #endif /* HAVE_BYTESWAP_H */ #define DBUS_UINT16_SWAP_LE_BE(val) (DBUS_UINT16_SWAP_LE_BE_CONSTANT (val)) #define DBUS_INT16_SWAP_LE_BE(val) ((dbus_int16_t)DBUS_UINT16_SWAP_LE_BE_CONSTANT (val)) #define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) #define DBUS_INT32_SWAP_LE_BE(val) ((dbus_int32_t)DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) #define DBUS_UINT64_SWAP_LE_BE(val) (DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) #define DBUS_INT64_SWAP_LE_BE(val) ((dbus_int64_t)DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) #ifdef WORDS_BIGENDIAN # define DBUS_INT16_TO_BE(val) ((dbus_int16_t) (val)) # define DBUS_UINT16_TO_BE(val) ((dbus_uint16_t) (val)) # define DBUS_INT16_TO_LE(val) (DBUS_INT16_SWAP_LE_BE (val)) # define DBUS_UINT16_TO_LE(val) (DBUS_UINT16_SWAP_LE_BE (val)) # define DBUS_INT32_TO_BE(val) ((dbus_int32_t) (val)) # define DBUS_UINT32_TO_BE(val) ((dbus_uint32_t) (val)) # define DBUS_INT32_TO_LE(val) (DBUS_INT32_SWAP_LE_BE (val)) # define DBUS_UINT32_TO_LE(val) (DBUS_UINT32_SWAP_LE_BE (val)) # define DBUS_INT64_TO_BE(val) ((dbus_int64_t) (val)) # define DBUS_UINT64_TO_BE(val) ((dbus_uint64_t) (val)) # define DBUS_INT64_TO_LE(val) (DBUS_INT64_SWAP_LE_BE (val)) # define DBUS_UINT64_TO_LE(val) (DBUS_UINT64_SWAP_LE_BE (val)) #else /* WORDS_BIGENDIAN */ # define DBUS_INT16_TO_LE(val) ((dbus_int16_t) (val)) # define DBUS_UINT16_TO_LE(val) ((dbus_uint16_t) (val)) # define DBUS_INT16_TO_BE(val) ((dbus_int16_t) DBUS_UINT16_SWAP_LE_BE (val)) # define DBUS_UINT16_TO_BE(val) (DBUS_UINT16_SWAP_LE_BE (val)) # define DBUS_INT32_TO_LE(val) ((dbus_int32_t) (val)) # define DBUS_UINT32_TO_LE(val) ((dbus_uint32_t) (val)) # define DBUS_INT32_TO_BE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val)) # define DBUS_UINT32_TO_BE(val) (DBUS_UINT32_SWAP_LE_BE (val)) # define DBUS_INT64_TO_LE(val) ((dbus_int64_t) (val)) # define DBUS_UINT64_TO_LE(val) ((dbus_uint64_t) (val)) # define DBUS_INT64_TO_BE(val) ((dbus_int64_t) DBUS_UINT64_SWAP_LE_BE (val)) # define DBUS_UINT64_TO_BE(val) (DBUS_UINT64_SWAP_LE_BE (val)) #endif /* The transformation is symmetric, so the FROM just maps to the TO. */ #define DBUS_INT16_FROM_LE(val) (DBUS_INT16_TO_LE (val)) #define DBUS_UINT16_FROM_LE(val) (DBUS_UINT16_TO_LE (val)) #define DBUS_INT16_FROM_BE(val) (DBUS_INT16_TO_BE (val)) #define DBUS_UINT16_FROM_BE(val) (DBUS_UINT16_TO_BE (val)) #define DBUS_INT32_FROM_LE(val) (DBUS_INT32_TO_LE (val)) #define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val)) #define DBUS_INT32_FROM_BE(val) (DBUS_INT32_TO_BE (val)) #define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val)) #define DBUS_INT64_FROM_LE(val) (DBUS_INT64_TO_LE (val)) #define DBUS_UINT64_FROM_LE(val) (DBUS_UINT64_TO_LE (val)) #define DBUS_INT64_FROM_BE(val) (DBUS_INT64_TO_BE (val)) #define DBUS_UINT64_FROM_BE(val) (DBUS_UINT64_TO_BE (val)) #ifdef DBUS_DISABLE_ASSERT #define _dbus_unpack_uint16(byte_order, data) \ (((byte_order) == DBUS_LITTLE_ENDIAN) ? \ DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)(data)) : \ DBUS_UINT16_FROM_BE (*(dbus_uint16_t*)(data))) #define _dbus_unpack_uint32(byte_order, data) \ (((byte_order) == DBUS_LITTLE_ENDIAN) ? \ DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)(data)) : \ DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)(data))) #endif #ifndef _dbus_unpack_uint16 DBUS_PRIVATE_EXPORT dbus_uint16_t _dbus_unpack_uint16 (int byte_order, const unsigned char *data); #endif void _dbus_pack_uint32 (dbus_uint32_t value, int byte_order, unsigned char *data); #ifndef _dbus_unpack_uint32 DBUS_PRIVATE_EXPORT dbus_uint32_t _dbus_unpack_uint32 (int byte_order, const unsigned char *data); #endif dbus_bool_t _dbus_marshal_set_basic (DBusString *str, int pos, int type, const void *value, int byte_order, int *old_end_pos, int *new_end_pos); dbus_bool_t _dbus_marshal_write_basic (DBusString *str, int insert_at, int type, const void *value, int byte_order, int *pos_after); dbus_bool_t _dbus_marshal_write_fixed_multi (DBusString *str, int insert_at, int element_type, const void *value, int n_elements, int byte_order, int *pos_after); void _dbus_marshal_read_basic (const DBusString *str, int pos, int type, void *value, int byte_order, int *new_pos); void _dbus_marshal_read_fixed_multi (const DBusString *str, int pos, int element_type, void *value, int n_elements, int byte_order, int *new_pos); void _dbus_marshal_skip_basic (const DBusString *str, int type, int byte_order, int *pos); void _dbus_marshal_skip_array (const DBusString *str, int element_type, int byte_order, int *pos); DBUS_PRIVATE_EXPORT void _dbus_marshal_set_uint32 (DBusString *str, int pos, dbus_uint32_t value, int byte_order); DBUS_PRIVATE_EXPORT dbus_uint32_t _dbus_marshal_read_uint32 (const DBusString *str, int pos, int byte_order, int *new_pos); int _dbus_type_get_alignment (int typecode); int _dbus_type_get_alignment (int typecode); DBUS_PRIVATE_EXPORT const char* _dbus_type_to_string (int typecode); DBUS_PRIVATE_EXPORT int _dbus_first_type_in_signature (const DBusString *str, int pos); int _dbus_first_type_in_signature_c_str (const char *str, int pos); void _dbus_swap_array (unsigned char *data, int n_elements, int alignment); #endif /* DBUS_MARSHAL_BASIC_H */ dbus-1.10.6/dbus/dbus-marshal-basic.c0000644000175000017500000016755512624705346017334 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-basic.c Marshalling routines for basic (primitive) types * * Copyright (C) 2002 CodeFactory AB * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-marshal-basic.h" #include "dbus-signature.h" #include #if defined(__GNUC__) && (__GNUC__ >= 4) # define _DBUS_ASSERT_ALIGNMENT(type, op, val) \ _DBUS_STATIC_ASSERT (__extension__ __alignof__ (type) op val) #else /* not gcc, so probably no alignof operator: just use a no-op statement * that's valid in the same contexts */ # define _DBUS_ASSERT_ALIGNMENT(type, op, val) \ _DBUS_STATIC_ASSERT (TRUE) #endif /* True by definition, but just for completeness... */ _DBUS_STATIC_ASSERT (sizeof (char) == 1); _DBUS_ASSERT_ALIGNMENT (char, ==, 1); _DBUS_STATIC_ASSERT (sizeof (dbus_int16_t) == 2); _DBUS_ASSERT_ALIGNMENT (dbus_int16_t, <=, 2); _DBUS_STATIC_ASSERT (sizeof (dbus_uint16_t) == 2); _DBUS_ASSERT_ALIGNMENT (dbus_uint16_t, <=, 2); _DBUS_STATIC_ASSERT (sizeof (dbus_int32_t) == 4); _DBUS_ASSERT_ALIGNMENT (dbus_int32_t, <=, 4); _DBUS_STATIC_ASSERT (sizeof (dbus_uint32_t) == 4); _DBUS_ASSERT_ALIGNMENT (dbus_uint32_t, <=, 4); _DBUS_STATIC_ASSERT (sizeof (dbus_bool_t) == 4); _DBUS_ASSERT_ALIGNMENT (dbus_bool_t, <=, 4); _DBUS_STATIC_ASSERT (sizeof (double) == 8); _DBUS_ASSERT_ALIGNMENT (double, <=, 8); _DBUS_STATIC_ASSERT (sizeof (dbus_int64_t) == 8); _DBUS_ASSERT_ALIGNMENT (dbus_int64_t, <=, 8); _DBUS_STATIC_ASSERT (sizeof (dbus_uint64_t) == 8); _DBUS_ASSERT_ALIGNMENT (dbus_uint64_t, <=, 8); _DBUS_STATIC_ASSERT (sizeof (DBusBasicValue) >= 8); /* The alignment of a DBusBasicValue might conceivably be > 8 because of the * pointer, so we don't assert about it */ _DBUS_STATIC_ASSERT (sizeof (DBus8ByteStruct) == 8); _DBUS_ASSERT_ALIGNMENT (DBus8ByteStruct, <=, 8); /** * @defgroup DBusMarshal marshaling and unmarshaling * @ingroup DBusInternals * @brief functions to marshal/unmarshal data from the wire * * Types and functions related to converting primitive data types from * wire format to native machine format, and vice versa. * * A signature is just a string with multiple types one after the other. * for example a type is "i" or "(ii)", a signature is "i(ii)" * where i is int and (ii) is struct { int; int; } * * @{ */ static void pack_2_octets (dbus_uint16_t value, int byte_order, unsigned char *data) { _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data); if ((byte_order) == DBUS_LITTLE_ENDIAN) *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_LE (value); else *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_BE (value); } static void pack_4_octets (dbus_uint32_t value, int byte_order, unsigned char *data) { _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); if ((byte_order) == DBUS_LITTLE_ENDIAN) *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value); else *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value); } static void pack_8_octets (DBusBasicValue value, int byte_order, unsigned char *data) { _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data); if ((byte_order) == DBUS_LITTLE_ENDIAN) *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_LE (value.u64); else *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_BE (value.u64); } /** * Packs a 32 bit unsigned integer into a data pointer. * * @param value the value * @param byte_order the byte order to use * @param data the data pointer */ void _dbus_pack_uint32 (dbus_uint32_t value, int byte_order, unsigned char *data) { pack_4_octets (value, byte_order, data); } static void swap_8_octets (DBusBasicValue *value, int byte_order) { if (byte_order != DBUS_COMPILER_BYTE_ORDER) { value->u64 = DBUS_UINT64_SWAP_LE_BE (value->u64); } } #ifndef _dbus_unpack_uint16 /** * Unpacks a 16 bit unsigned integer from a data pointer * * @param byte_order The byte order to use * @param data the data pointer * @returns the integer */ dbus_uint16_t _dbus_unpack_uint16 (int byte_order, const unsigned char *data) { _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data); if (byte_order == DBUS_LITTLE_ENDIAN) return DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)data); else return DBUS_UINT16_FROM_BE (*(dbus_uint16_t*)data); } #endif /* _dbus_unpack_uint16 */ #ifndef _dbus_unpack_uint32 /** * Unpacks a 32 bit unsigned integer from a data pointer * * @param byte_order The byte order to use * @param data the data pointer * @returns the integer */ dbus_uint32_t _dbus_unpack_uint32 (int byte_order, const unsigned char *data) { _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); if (byte_order == DBUS_LITTLE_ENDIAN) return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data); else return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data); } #endif /* _dbus_unpack_uint32 */ static void set_2_octets (DBusString *str, int offset, dbus_uint16_t value, int byte_order) { char *data; _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); data = _dbus_string_get_data_len (str, offset, 2); pack_2_octets (value, byte_order, data); } static void set_4_octets (DBusString *str, int offset, dbus_uint32_t value, int byte_order) { char *data; _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); data = _dbus_string_get_data_len (str, offset, 4); pack_4_octets (value, byte_order, data); } static void set_8_octets (DBusString *str, int offset, DBusBasicValue value, int byte_order) { char *data; _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); data = _dbus_string_get_data_len (str, offset, 8); pack_8_octets (value, byte_order, data); } /** * Sets the 4 bytes at the given offset to a marshaled unsigned * integer, replacing anything found there previously. * * @param str the string to write the marshalled int to * @param pos the byte offset where int should be written * @param value the value * @param byte_order the byte order to use * */ void _dbus_marshal_set_uint32 (DBusString *str, int pos, dbus_uint32_t value, int byte_order) { set_4_octets (str, pos, value, byte_order); } /** * Sets the existing marshaled string at the given offset with * a new marshaled string. The given offset must point to * an existing string or the wrong length will be deleted * and replaced with the new string. * * Note: no attempt is made by this function to re-align * any data which has been already marshalled after this * string. Use with caution. * * @param str the string to write the marshalled string to * @param pos the position of the marshaled string length * @param value the value * @param byte_order the byte order to use * @param old_end_pos place to store byte after the nul byte of the old value * @param new_end_pos place to store byte after the nul byte of the new value * @returns #TRUE on success, #FALSE if no memory * */ static dbus_bool_t set_string (DBusString *str, int pos, const char *value, int byte_order, int *old_end_pos, int *new_end_pos) { int old_len, new_len; DBusString dstr; _dbus_string_init_const (&dstr, value); _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned) pos); old_len = _dbus_unpack_uint32 (byte_order, _dbus_string_get_const_data_len (str, pos, 4)); new_len = _dbus_string_get_length (&dstr); if (!_dbus_string_replace_len (&dstr, 0, new_len, str, pos + 4, old_len)) return FALSE; _dbus_marshal_set_uint32 (str, pos, new_len, byte_order); if (old_end_pos) *old_end_pos = pos + 4 + old_len + 1; if (new_end_pos) *new_end_pos = pos + 4 + new_len + 1; return TRUE; } /** * Sets the existing marshaled signature at the given offset to a new * marshaled signature. Same basic ideas as set_string(). * * @param str the string to write the marshalled signature to * @param pos the position of the marshaled signature length * @param value the value * @param byte_order the byte order to use * @param old_end_pos place to store byte after the nul byte of the old value * @param new_end_pos place to store byte after the nul byte of the new value * @returns #TRUE on success, #FALSE if no memory * */ static dbus_bool_t set_signature (DBusString *str, int pos, const char *value, int byte_order, int *old_end_pos, int *new_end_pos) { int old_len, new_len; DBusString dstr; _dbus_string_init_const (&dstr, value); old_len = _dbus_string_get_byte (str, pos); new_len = _dbus_string_get_length (&dstr); if (!_dbus_string_replace_len (&dstr, 0, new_len, str, pos + 1, old_len)) return FALSE; _dbus_string_set_byte (str, pos, new_len); if (old_end_pos) *old_end_pos = pos + 1 + old_len + 1; if (new_end_pos) *new_end_pos = pos + 1 + new_len + 1; return TRUE; } /** * Sets an existing basic type value to a new value. * Arguments work the same way as _dbus_marshal_basic_type(). * * @param str the string * @param pos location of the current value * @param type the type of the current and new values * @param value the address of the new value * @param byte_order byte order for marshaling * @param old_end_pos location to store end position of the old value, or #NULL * @param new_end_pos location to store end position of the new value, or #NULL * @returns #FALSE if no memory */ dbus_bool_t _dbus_marshal_set_basic (DBusString *str, int pos, int type, const void *value, int byte_order, int *old_end_pos, int *new_end_pos) { const DBusBasicValue *vp; vp = value; switch (type) { case DBUS_TYPE_BYTE: _dbus_string_set_byte (str, pos, vp->byt); if (old_end_pos) *old_end_pos = pos + 1; if (new_end_pos) *new_end_pos = pos + 1; return TRUE; break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: pos = _DBUS_ALIGN_VALUE (pos, 2); set_2_octets (str, pos, vp->u16, byte_order); if (old_end_pos) *old_end_pos = pos + 2; if (new_end_pos) *new_end_pos = pos + 2; return TRUE; break; case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: pos = _DBUS_ALIGN_VALUE (pos, 4); set_4_octets (str, pos, vp->u32, byte_order); if (old_end_pos) *old_end_pos = pos + 4; if (new_end_pos) *new_end_pos = pos + 4; return TRUE; break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: pos = _DBUS_ALIGN_VALUE (pos, 8); set_8_octets (str, pos, *vp, byte_order); if (old_end_pos) *old_end_pos = pos + 8; if (new_end_pos) *new_end_pos = pos + 8; return TRUE; break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: pos = _DBUS_ALIGN_VALUE (pos, 4); _dbus_assert (vp->str != NULL); return set_string (str, pos, vp->str, byte_order, old_end_pos, new_end_pos); break; case DBUS_TYPE_SIGNATURE: _dbus_assert (vp->str != NULL); return set_signature (str, pos, vp->str, byte_order, old_end_pos, new_end_pos); break; default: _dbus_assert_not_reached ("not a basic type"); return FALSE; break; } } /** * Convenience function to demarshal a 32 bit unsigned integer. * * @param str the string containing the data * @param byte_order the byte order * @param pos the position in the string * @param new_pos the new position of the string * @returns the demarshaled integer. */ dbus_uint32_t _dbus_marshal_read_uint32 (const DBusString *str, int pos, int byte_order, int *new_pos) { pos = _DBUS_ALIGN_VALUE (pos, 4); if (new_pos) *new_pos = pos + 4; _dbus_assert (pos + 4 <= _dbus_string_get_length (str)); return _dbus_unpack_uint32 (byte_order, _dbus_string_get_const_data (str) + pos); } /** * Demarshals a basic-typed value. The "value" pointer is always * the address of a variable of the basic type. So e.g. * if the basic type is "double" then the pointer is * a double*, and if it's "char*" then the pointer is * a "char**". * * A value of type #DBusBasicValue is guaranteed to be large enough to * hold any of the types that may be returned, which is handy if you * are trying to do things generically. For example you can pass * a DBusBasicValue* in to this function, and then pass the same * DBusBasicValue* in to _dbus_marshal_basic_type() in order to * move a value from one place to another. * * @param str the string containing the data * @param pos position in the string * @param type type of value to demarshal * @param value pointer to return value data * @param byte_order the byte order * @param new_pos pointer to update with new position, or #NULL **/ void _dbus_marshal_read_basic (const DBusString *str, int pos, int type, void *value, int byte_order, int *new_pos) { const char *str_data; _dbus_assert (dbus_type_is_basic (type)); str_data = _dbus_string_get_const_data (str); /* Below we volatile types to avoid aliasing issues; * see http://bugs.freedesktop.org/show_bug.cgi?id=20137 */ switch (type) { case DBUS_TYPE_BYTE: { volatile unsigned char *vp = value; *vp = (unsigned char) _dbus_string_get_byte (str, pos); (pos)++; } break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: { volatile dbus_uint16_t *vp = value; pos = _DBUS_ALIGN_VALUE (pos, 2); *vp = *(dbus_uint16_t *)(str_data + pos); if (byte_order != DBUS_COMPILER_BYTE_ORDER) *vp = DBUS_UINT16_SWAP_LE_BE (*vp); pos += 2; } break; case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_UNIX_FD: { volatile dbus_uint32_t *vp = value; pos = _DBUS_ALIGN_VALUE (pos, 4); *vp = *(dbus_uint32_t *)(str_data + pos); if (byte_order != DBUS_COMPILER_BYTE_ORDER) *vp = DBUS_UINT32_SWAP_LE_BE (*vp); pos += 4; } break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: { volatile dbus_uint64_t *vp = value; pos = _DBUS_ALIGN_VALUE (pos, 8); if (byte_order != DBUS_COMPILER_BYTE_ORDER) *vp = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t*)(str_data + pos)); else *vp = *(dbus_uint64_t*)(str_data + pos); pos += 8; } break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: { int len; volatile char **vp = value; len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos); *vp = (char*) str_data + pos; pos += len + 1; /* length plus nul */ } break; case DBUS_TYPE_SIGNATURE: { int len; volatile char **vp = value; len = _dbus_string_get_byte (str, pos); pos += 1; *vp = (char*) str_data + pos; pos += len + 1; /* length plus nul */ } break; default: _dbus_warn_check_failed ("type %s %d not a basic type\n", _dbus_type_to_string (type), type); _dbus_assert_not_reached ("not a basic type"); break; } if (new_pos) *new_pos = pos; } static dbus_bool_t marshal_2_octets (DBusString *str, int insert_at, dbus_uint16_t value, int byte_order, int *pos_after) { dbus_bool_t retval; int orig_len; _DBUS_STATIC_ASSERT (sizeof (value) == 2); if (byte_order != DBUS_COMPILER_BYTE_ORDER) value = DBUS_UINT16_SWAP_LE_BE (value); orig_len = _dbus_string_get_length (str); retval = _dbus_string_insert_2_aligned (str, insert_at, (const unsigned char *)&value); if (pos_after) { *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len); _dbus_assert (*pos_after <= _dbus_string_get_length (str)); } return retval; } static dbus_bool_t marshal_4_octets (DBusString *str, int insert_at, dbus_uint32_t value, int byte_order, int *pos_after) { dbus_bool_t retval; int orig_len; _DBUS_STATIC_ASSERT (sizeof (value) == 4); if (byte_order != DBUS_COMPILER_BYTE_ORDER) value = DBUS_UINT32_SWAP_LE_BE (value); orig_len = _dbus_string_get_length (str); retval = _dbus_string_insert_4_aligned (str, insert_at, (const unsigned char *)&value); if (pos_after) { *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len); _dbus_assert (*pos_after <= _dbus_string_get_length (str)); } return retval; } static dbus_bool_t marshal_8_octets (DBusString *str, int insert_at, DBusBasicValue value, int byte_order, int *pos_after) { dbus_bool_t retval; int orig_len; _DBUS_STATIC_ASSERT (sizeof (value) == 8); swap_8_octets (&value, byte_order); orig_len = _dbus_string_get_length (str); retval = _dbus_string_insert_8_aligned (str, insert_at, (const unsigned char *)&value); if (pos_after) *pos_after = insert_at + _dbus_string_get_length (str) - orig_len; return retval; } enum { MARSHAL_AS_STRING, MARSHAL_AS_SIGNATURE, MARSHAL_AS_BYTE_ARRAY }; static dbus_bool_t marshal_len_followed_by_bytes (int marshal_as, DBusString *str, int insert_at, const unsigned char *value, int data_len, /* doesn't include nul if any */ int byte_order, int *pos_after) { int pos; DBusString value_str; int value_len; _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); if (insert_at > _dbus_string_get_length (str)) _dbus_warn ("insert_at = %d string len = %d data_len = %d\n", insert_at, _dbus_string_get_length (str), data_len); if (marshal_as == MARSHAL_AS_BYTE_ARRAY) value_len = data_len; else value_len = data_len + 1; /* value has a nul */ _dbus_string_init_const_len (&value_str, value, value_len); pos = insert_at; if (marshal_as == MARSHAL_AS_SIGNATURE) { _dbus_assert (data_len <= DBUS_MAXIMUM_SIGNATURE_LENGTH); _dbus_assert (data_len <= 255); /* same as max sig len right now */ if (!_dbus_string_insert_byte (str, pos, data_len)) goto oom; pos += 1; } else { if (!marshal_4_octets (str, pos, data_len, byte_order, &pos)) goto oom; } if (!_dbus_string_copy_len (&value_str, 0, value_len, str, pos)) goto oom; #if 0 /* too expensive */ _dbus_assert (_dbus_string_equal_substring (&value_str, 0, value_len, str, pos)); _dbus_verbose_bytes_of_string (str, pos, value_len); #endif pos += value_len; if (pos_after) *pos_after = pos; return TRUE; oom: /* Delete what we've inserted */ _dbus_string_delete (str, insert_at, pos - insert_at); return FALSE; } static dbus_bool_t marshal_string (DBusString *str, int insert_at, const char *value, int byte_order, int *pos_after) { return marshal_len_followed_by_bytes (MARSHAL_AS_STRING, str, insert_at, value, strlen (value), byte_order, pos_after); } static dbus_bool_t marshal_signature (DBusString *str, int insert_at, const char *value, int *pos_after) { return marshal_len_followed_by_bytes (MARSHAL_AS_SIGNATURE, str, insert_at, value, strlen (value), DBUS_COMPILER_BYTE_ORDER, /* irrelevant */ pos_after); } /** * Marshals a basic-typed value. The "value" pointer is always the * address of a variable containing the basic type value. * So for example for int32 it will be dbus_int32_t*, and * for string it will be const char**. This is for symmetry * with _dbus_marshal_read_basic() and to have a simple * consistent rule. * * @param str string to marshal to * @param insert_at where to insert the value * @param type type of value * @param value pointer to a variable containing the value * @param byte_order byte order * @param pos_after #NULL or the position after the type * @returns #TRUE on success **/ dbus_bool_t _dbus_marshal_write_basic (DBusString *str, int insert_at, int type, const void *value, int byte_order, int *pos_after) { const DBusBasicValue *vp; _dbus_assert (dbus_type_is_basic (type)); vp = value; switch (type) { case DBUS_TYPE_BYTE: if (!_dbus_string_insert_byte (str, insert_at, vp->byt)) return FALSE; if (pos_after) *pos_after = insert_at + 1; return TRUE; break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: return marshal_2_octets (str, insert_at, vp->u16, byte_order, pos_after); break; case DBUS_TYPE_BOOLEAN: return marshal_4_octets (str, insert_at, vp->u32 != FALSE, byte_order, pos_after); break; case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: return marshal_4_octets (str, insert_at, vp->u32, byte_order, pos_after); break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: return marshal_8_octets (str, insert_at, *vp, byte_order, pos_after); break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: _dbus_assert (vp->str != NULL); return marshal_string (str, insert_at, vp->str, byte_order, pos_after); break; case DBUS_TYPE_SIGNATURE: _dbus_assert (vp->str != NULL); return marshal_signature (str, insert_at, vp->str, pos_after); break; default: _dbus_assert_not_reached ("not a basic type"); return FALSE; break; } } static dbus_bool_t marshal_1_octets_array (DBusString *str, int insert_at, const unsigned char *value, int n_elements, int byte_order, int *pos_after) { int pos; DBusString value_str; _dbus_string_init_const_len (&value_str, value, n_elements); pos = insert_at; if (!_dbus_string_copy_len (&value_str, 0, n_elements, str, pos)) return FALSE; pos += n_elements; if (pos_after) *pos_after = pos; return TRUE; } /** * Swaps the elements of an array to the opposite byte order * * @param data start of array * @param n_elements number of elements * @param alignment size of each element */ void _dbus_swap_array (unsigned char *data, int n_elements, int alignment) { unsigned char *d; unsigned char *end; _dbus_assert (_DBUS_ALIGN_ADDRESS (data, alignment) == data); /* we use const_data and cast it off so DBusString can be a const string * for the unit tests. don't ask. */ d = data; end = d + (n_elements * alignment); if (alignment == 8) { while (d != end) { *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); d += 8; } } else if (alignment == 4) { while (d != end) { *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d)); d += 4; } } else { _dbus_assert (alignment == 2); while (d != end) { *((dbus_uint16_t*)d) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)d)); d += 2; } } } static void swap_array (DBusString *str, int array_start, int n_elements, int byte_order, int alignment) { _dbus_assert (_DBUS_ALIGN_VALUE (array_start, alignment) == (unsigned) array_start); if (byte_order != DBUS_COMPILER_BYTE_ORDER) { /* we use const_data and cast it off so DBusString can be a const string * for the unit tests. don't ask. */ _dbus_swap_array ((unsigned char*) (_dbus_string_get_const_data (str) + array_start), n_elements, alignment); } } static dbus_bool_t marshal_fixed_multi (DBusString *str, int insert_at, const DBusBasicValue *value, int n_elements, int byte_order, int alignment, int *pos_after) { int old_string_len; int array_start; DBusString t; int len_in_bytes; _dbus_assert (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / alignment); old_string_len = _dbus_string_get_length (str); len_in_bytes = n_elements * alignment; array_start = insert_at; /* Note that we do alignment padding unconditionally * even if the array is empty; this means that * padding + len is always equal to the number of bytes * in the array. */ if (!_dbus_string_insert_alignment (str, &array_start, alignment)) goto error; _dbus_string_init_const_len (&t, (const unsigned char*) value, len_in_bytes); if (!_dbus_string_copy (&t, 0, str, array_start)) goto error; swap_array (str, array_start, n_elements, byte_order, alignment); if (pos_after) *pos_after = array_start + len_in_bytes; return TRUE; error: _dbus_string_delete (str, insert_at, _dbus_string_get_length (str) - old_string_len); return FALSE; } /** * Marshals a block of values of fixed-length type all at once, as an * optimization. dbus_type_is_fixed() returns #TRUE for fixed-length * types, which are the basic types minus the string-like types. * * The value argument should be the adddress of an * array, so e.g. "const dbus_uint32_t**" * * @param str string to marshal to * @param insert_at where to insert the value * @param element_type type of array elements * @param value address of an array to marshal * @param n_elements number of elements in the array * @param byte_order byte order * @param pos_after #NULL or the position after the type * @returns #TRUE on success **/ dbus_bool_t _dbus_marshal_write_fixed_multi (DBusString *str, int insert_at, int element_type, const void *value, int n_elements, int byte_order, int *pos_after) { const void* vp = *(const DBusBasicValue**)value; _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (n_elements >= 0); #if 0 _dbus_verbose ("writing %d elements of %s\n", n_elements, _dbus_type_to_string (element_type)); #endif switch (element_type) { case DBUS_TYPE_BYTE: return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after); break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 2, pos_after); case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after); break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 8, pos_after); break; default: _dbus_assert_not_reached ("non fixed type in array write"); break; } return FALSE; } /** * Skips over a basic-typed value, reporting the following position. * * @param str the string containing the data * @param type type of value to read * @param byte_order the byte order * @param pos pointer to position in the string, * updated on return to new position **/ void _dbus_marshal_skip_basic (const DBusString *str, int type, int byte_order, int *pos) { _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); switch (type) { case DBUS_TYPE_BYTE: (*pos)++; break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: *pos = _DBUS_ALIGN_VALUE (*pos, 2); *pos += 2; break; case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: *pos = _DBUS_ALIGN_VALUE (*pos, 4); *pos += 4; break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: *pos = _DBUS_ALIGN_VALUE (*pos, 8); *pos += 8; break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: { int len; len = _dbus_marshal_read_uint32 (str, *pos, byte_order, pos); *pos += len + 1; /* length plus nul */ } break; case DBUS_TYPE_SIGNATURE: { int len; len = _dbus_string_get_byte (str, *pos); *pos += len + 2; /* length byte plus length plus nul */ } break; default: _dbus_warn ("type %s not a basic type\n", _dbus_type_to_string (type)); _dbus_assert_not_reached ("not a basic type"); break; } } /** * Skips an array, returning the next position. * * @param str the string containing the data * @param element_type the type of array elements * @param byte_order the byte order * @param pos pointer to position in the string, * updated on return to new position */ void _dbus_marshal_skip_array (const DBusString *str, int element_type, int byte_order, int *pos) { dbus_uint32_t array_len; int i; int alignment; i = _DBUS_ALIGN_VALUE (*pos, 4); array_len = _dbus_marshal_read_uint32 (str, i, byte_order, &i); alignment = _dbus_type_get_alignment (element_type); i = _DBUS_ALIGN_VALUE (i, alignment); *pos = i + array_len; } /** * Gets the alignment requirement for the given type; * will be 1, 4, or 8. * * @param typecode the type * @returns alignment of 1, 4, or 8 */ int _dbus_type_get_alignment (int typecode) { switch (typecode) { case DBUS_TYPE_BYTE: case DBUS_TYPE_VARIANT: case DBUS_TYPE_SIGNATURE: return 1; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: return 2; case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: /* this stuff is 4 since it starts with a length */ case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_ARRAY: return 4; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: /* struct is 8 since it could contain an 8-aligned item * and it's simpler to just always align structs to 8; * we want the amount of padding in a struct of a given * type to be predictable, not location-dependent. * DICT_ENTRY is always the same as struct. */ case DBUS_TYPE_STRUCT: case DBUS_TYPE_DICT_ENTRY: return 8; default: _dbus_assert_not_reached ("unknown typecode in _dbus_type_get_alignment()"); return 0; } } /** * Returns a string describing the given type. * * @param typecode the type to describe * @returns a constant string describing the type */ const char * _dbus_type_to_string (int typecode) { switch (typecode) { case DBUS_TYPE_INVALID: return "invalid"; case DBUS_TYPE_BOOLEAN: return "boolean"; case DBUS_TYPE_BYTE: return "byte"; case DBUS_TYPE_INT16: return "int16"; case DBUS_TYPE_UINT16: return "uint16"; case DBUS_TYPE_INT32: return "int32"; case DBUS_TYPE_UINT32: return "uint32"; case DBUS_TYPE_INT64: return "int64"; case DBUS_TYPE_UINT64: return "uint64"; case DBUS_TYPE_DOUBLE: return "double"; case DBUS_TYPE_STRING: return "string"; case DBUS_TYPE_OBJECT_PATH: return "object_path"; case DBUS_TYPE_SIGNATURE: return "signature"; case DBUS_TYPE_STRUCT: return "struct"; case DBUS_TYPE_DICT_ENTRY: return "dict_entry"; case DBUS_TYPE_ARRAY: return "array"; case DBUS_TYPE_VARIANT: return "variant"; case DBUS_STRUCT_BEGIN_CHAR: return "begin_struct"; case DBUS_STRUCT_END_CHAR: return "end_struct"; case DBUS_DICT_ENTRY_BEGIN_CHAR: return "begin_dict_entry"; case DBUS_DICT_ENTRY_END_CHAR: return "end_dict_entry"; case DBUS_TYPE_UNIX_FD: return "unix_fd"; default: return "unknown"; } } /** * If in verbose mode, print a block of binary data. * * @param data the data * @param len the length of the data * @param offset where to start counting for byte indexes */ void _dbus_verbose_bytes (const unsigned char *data, int len, int offset) { int i; const unsigned char *aligned; _dbus_assert (len >= 0); if (!_dbus_is_verbose()) return; /* Print blanks on first row if appropriate */ aligned = _DBUS_ALIGN_ADDRESS (data, 4); if (aligned > data) aligned -= 4; _dbus_assert (aligned <= data); if (aligned != data) { _dbus_verbose ("%4ld\t%p: ", - (long)(data - aligned), aligned); while (aligned != data) { _dbus_verbose (" "); ++aligned; } } /* now print the bytes */ i = 0; while (i < len) { if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) { _dbus_verbose ("%4d\t%p: ", offset + i, &data[i]); } if (data[i] >= 32 && data[i] <= 126) _dbus_verbose (" '%c' ", data[i]); else _dbus_verbose ("0x%s%x ", data[i] <= 0xf ? "0" : "", data[i]); ++i; if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) { if (i > 3) _dbus_verbose ("BE: %d LE: %d", _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]), _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4])); if (i > 7 && _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i]) { #ifdef DBUS_INT64_PRINTF_MODIFIER _dbus_verbose (" u64: 0x%" DBUS_INT64_PRINTF_MODIFIER "x", *(dbus_uint64_t*)&data[i-8]); #endif _dbus_verbose (" dbl: %g", *(double*)&data[i-8]); } _dbus_verbose ("\n"); } } _dbus_verbose ("\n"); } /** * Dump the given part of the string to verbose log. * * @param str the string * @param start the start of range to dump * @param len length of range */ void _dbus_verbose_bytes_of_string (const DBusString *str, int start, int len) { const char *d; int real_len; real_len = _dbus_string_get_length (str); _dbus_assert (start >= 0); if (start > real_len) { _dbus_verbose (" [%d,%d) is not inside string of length %d\n", start, len, real_len); return; } if ((start + len) > real_len) { _dbus_verbose (" [%d,%d) extends outside string of length %d\n", start, len, real_len); len = real_len - start; } d = _dbus_string_get_const_data_len (str, start, len); _dbus_verbose_bytes (d, len, start); } static int map_type_char_to_type (int t) { if (t == DBUS_STRUCT_BEGIN_CHAR) return DBUS_TYPE_STRUCT; else if (t == DBUS_DICT_ENTRY_BEGIN_CHAR) return DBUS_TYPE_DICT_ENTRY; else { _dbus_assert (t != DBUS_STRUCT_END_CHAR); _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR); return t; } } /** * Get the first type in the signature. The difference between this * and just getting the first byte of the signature is that you won't * get DBUS_STRUCT_BEGIN_CHAR, you'll get DBUS_TYPE_STRUCT * instead. * * @param str string containing signature * @param pos where the signature starts * @returns the first type in the signature */ int _dbus_first_type_in_signature (const DBusString *str, int pos) { return map_type_char_to_type (_dbus_string_get_byte (str, pos)); } /** * Similar to #_dbus_first_type_in_signature, but operates * on a C string buffer. * * @param str a C string buffer * @param pos where the signature starts * @returns the first type in the signature */ int _dbus_first_type_in_signature_c_str (const char *str, int pos) { return map_type_char_to_type (str[pos]); } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include /** * Reads a block of fixed-length basic values, as an optimization * vs. reading each one individually into a new buffer. * * This function returns the data in-place; it does not make a copy, * and it does not swap the bytes. * * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back * and the "value" argument should be a "const double**" and so on. * * @param str the string to read from * @param pos position to read from * @param element_type type of array elements * @param value place to return the array * @param n_elements number of array elements to read * @param byte_order the byte order, used to read the array length * @param new_pos #NULL or location to store a position after the elements */ void _dbus_marshal_read_fixed_multi (const DBusString *str, int pos, int element_type, void *value, int n_elements, int byte_order, int *new_pos) { int array_len; int alignment; _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (dbus_type_is_basic (element_type)); #if 0 _dbus_verbose ("reading %d elements of %s\n", n_elements, _dbus_type_to_string (element_type)); #endif alignment = _dbus_type_get_alignment (element_type); pos = _DBUS_ALIGN_VALUE (pos, alignment); array_len = n_elements * alignment; *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len); if (new_pos) *new_pos = pos + array_len; } static void swap_test_array (void *array, int len_bytes, int byte_order, int alignment) { DBusString t; if (alignment == 1) return; _dbus_string_init_const_len (&t, array, len_bytes); swap_array (&t, 0, len_bytes / alignment, byte_order, alignment); } #define MARSHAL_BASIC(typename, byte_order, literal) \ do { \ v_##typename = literal; \ if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_##typename, \ &v_##typename, \ byte_order, NULL)) \ _dbus_assert_not_reached ("no memory"); \ } while (0) #define DEMARSHAL_BASIC(typename, byte_order) \ do { \ _dbus_marshal_read_basic (&str, pos, DBUS_TYPE_##typename, &v_##typename, \ byte_order, &pos); \ } while (0) #define DEMARSHAL_BASIC_AND_CHECK(typename, byte_order, literal) \ do { \ DEMARSHAL_BASIC (typename, byte_order); \ if (literal != v_##typename) \ { \ _dbus_verbose_bytes_of_string (&str, dump_pos, \ _dbus_string_get_length (&str) - dump_pos); \ _dbus_assert_not_reached ("demarshaled wrong value"); \ } \ } while (0) #define MARSHAL_TEST(typename, byte_order, literal) \ do { \ MARSHAL_BASIC (typename, byte_order, literal); \ dump_pos = pos; \ DEMARSHAL_BASIC_AND_CHECK (typename, byte_order, literal); \ } while (0) #define MARSHAL_TEST_STRCMP(typename, byte_order, literal) \ do { \ MARSHAL_BASIC (typename, byte_order, literal); \ dump_pos = pos; \ DEMARSHAL_BASIC (typename, byte_order); \ if (strcmp (literal, v_##typename) != 0) \ { \ _dbus_verbose_bytes_of_string (&str, dump_pos, \ _dbus_string_get_length (&str) - dump_pos); \ _dbus_warn ("literal '%s'\nvalue '%s'\n", literal, v_##typename); \ _dbus_assert_not_reached ("demarshaled wrong value"); \ } \ } while (0) #define MARSHAL_FIXED_ARRAY(typename, byte_order, literal) \ do { \ int next; \ v_UINT32 = sizeof(literal); \ if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_UINT32, &v_UINT32, \ byte_order, &next)) \ _dbus_assert_not_reached ("no memory"); \ v_ARRAY_##typename = literal; \ if (!_dbus_marshal_write_fixed_multi (&str, next, DBUS_TYPE_##typename, \ &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal), \ byte_order, NULL)) \ _dbus_assert_not_reached ("no memory"); \ } while (0) #define DEMARSHAL_FIXED_ARRAY(typename, byte_order) \ do { \ int next; \ alignment = _dbus_type_get_alignment (DBUS_TYPE_##typename); \ v_UINT32 = _dbus_marshal_read_uint32 (&str, dump_pos, byte_order, &next); \ _dbus_marshal_read_fixed_multi (&str, next, DBUS_TYPE_##typename, &v_ARRAY_##typename, \ v_UINT32/alignment, \ byte_order, NULL); \ swap_test_array (v_ARRAY_##typename, v_UINT32, \ byte_order, alignment); \ } while (0) #define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal) \ do { \ DEMARSHAL_FIXED_ARRAY (typename, byte_order); \ if (memcmp (literal, v_ARRAY_##typename, sizeof (literal)) != 0) \ { \ _dbus_verbose ("MARSHALED DATA\n"); \ _dbus_verbose_bytes_of_string (&str, dump_pos, \ _dbus_string_get_length (&str) - dump_pos); \ _dbus_verbose ("LITERAL DATA\n"); \ _dbus_verbose_bytes ((char*)literal, sizeof (literal), 0); \ _dbus_verbose ("READ DATA\n"); \ _dbus_verbose_bytes ((char*)v_ARRAY_##typename, sizeof (literal), 0); \ _dbus_assert_not_reached ("demarshaled wrong fixed array value"); \ } \ } while (0) #define MARSHAL_TEST_FIXED_ARRAY(typename, byte_order, literal) \ do { \ MARSHAL_FIXED_ARRAY (typename, byte_order, literal); \ dump_pos = pos; \ DEMARSHAL_FIXED_ARRAY_AND_CHECK (typename, byte_order, literal); \ } while (0) dbus_bool_t _dbus_marshal_test (void) { int alignment; DBusString str; int pos, dump_pos; unsigned char array1[5] = { 3, 4, 0, 1, 9 }; dbus_int16_t array2[3] = { 124, 457, 780 }; dbus_int32_t array4[3] = { 123, 456, 789 }; dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff), DBUS_INT64_CONSTANT (0x456ffffffff), DBUS_INT64_CONSTANT (0x789ffffffff) }; dbus_int64_t *v_ARRAY_INT64; unsigned char *v_ARRAY_BYTE; dbus_int16_t *v_ARRAY_INT16; dbus_uint16_t *v_ARRAY_UINT16; dbus_int32_t *v_ARRAY_INT32; dbus_uint32_t *v_ARRAY_UINT32; DBusString t; double v_DOUBLE; double t_DOUBLE; dbus_int16_t v_INT16; dbus_uint16_t v_UINT16; dbus_int32_t v_INT32; dbus_uint32_t v_UINT32; dbus_int64_t v_INT64; dbus_uint64_t v_UINT64; unsigned char v_BYTE; dbus_bool_t v_BOOLEAN; const char *v_STRING; const char *v_SIGNATURE; const char *v_OBJECT_PATH; int byte_order; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); pos = 0; /* Marshal doubles */ MARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN, 3.14); DEMARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN); t_DOUBLE = 3.14; if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE)) _dbus_assert_not_reached ("got wrong double value"); MARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN, 3.14); DEMARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN); t_DOUBLE = 3.14; if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE)) _dbus_assert_not_reached ("got wrong double value"); /* Marshal signed 16 integers */ MARSHAL_TEST (INT16, DBUS_BIG_ENDIAN, -12345); MARSHAL_TEST (INT16, DBUS_LITTLE_ENDIAN, -12345); /* Marshal unsigned 16 integers */ MARSHAL_TEST (UINT16, DBUS_BIG_ENDIAN, 0x1234); MARSHAL_TEST (UINT16, DBUS_LITTLE_ENDIAN, 0x1234); /* Marshal signed integers */ MARSHAL_TEST (INT32, DBUS_BIG_ENDIAN, -12345678); MARSHAL_TEST (INT32, DBUS_LITTLE_ENDIAN, -12345678); /* Marshal unsigned integers */ MARSHAL_TEST (UINT32, DBUS_BIG_ENDIAN, 0x12345678); MARSHAL_TEST (UINT32, DBUS_LITTLE_ENDIAN, 0x12345678); /* Marshal signed integers */ MARSHAL_TEST (INT64, DBUS_BIG_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7)); MARSHAL_TEST (INT64, DBUS_LITTLE_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7)); /* Marshal unsigned integers */ MARSHAL_TEST (UINT64, DBUS_BIG_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7)); MARSHAL_TEST (UINT64, DBUS_LITTLE_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7)); /* Marshal byte */ MARSHAL_TEST (BYTE, DBUS_BIG_ENDIAN, 5); MARSHAL_TEST (BYTE, DBUS_LITTLE_ENDIAN, 5); /* Marshal all possible bools! */ MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, FALSE); MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, FALSE); MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, TRUE); MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, TRUE); /* Marshal strings */ MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, ""); MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, ""); MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, "This is the dbus test string"); MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, "This is the dbus test string"); /* object paths */ MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_BIG_ENDIAN, "/a/b/c"); MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_LITTLE_ENDIAN, "/a/b/c"); /* signatures */ MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, ""); MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, ""); MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "a(ii)"); MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)"); /* Arrays */ MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_BIG_ENDIAN, array2); MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_LITTLE_ENDIAN, array2); MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_BIG_ENDIAN, array2); MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_LITTLE_ENDIAN, array2); MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4); MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4); MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_BIG_ENDIAN, array4); MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_LITTLE_ENDIAN, array4); MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_BIG_ENDIAN, array1); MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_LITTLE_ENDIAN, array1); MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8); MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8); #if 0 /* * FIXME restore the set/pack tests */ /* set/pack 64-bit integers */ _dbus_string_set_length (&str, 8); /* signed little */ _dbus_marshal_set_int64 (&str, DBUS_LITTLE_ENDIAN, 0, DBUS_INT64_CONSTANT (-0x123456789abc7)); _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* signed big */ _dbus_marshal_set_int64 (&str, DBUS_BIG_ENDIAN, 0, DBUS_INT64_CONSTANT (-0x123456789abc7)); _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == _dbus_unpack_int64 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* signed little pack */ _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), DBUS_LITTLE_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* signed big pack */ _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), DBUS_BIG_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == _dbus_unpack_int64 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned little */ _dbus_marshal_set_uint64 (&str, DBUS_LITTLE_ENDIAN, 0, DBUS_UINT64_CONSTANT (0x123456789abc7)); _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned big */ _dbus_marshal_set_uint64 (&str, DBUS_BIG_ENDIAN, 0, DBUS_UINT64_CONSTANT (0x123456789abc7)); _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned little pack */ _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), DBUS_LITTLE_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned big pack */ _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), DBUS_BIG_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* set/pack 32-bit integers */ _dbus_string_set_length (&str, 4); /* signed little */ _dbus_marshal_set_int32 (&str, DBUS_LITTLE_ENDIAN, 0, -0x123456); _dbus_assert (-0x123456 == _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* signed big */ _dbus_marshal_set_int32 (&str, DBUS_BIG_ENDIAN, 0, -0x123456); _dbus_assert (-0x123456 == _dbus_unpack_int32 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* signed little pack */ _dbus_pack_int32 (-0x123456, DBUS_LITTLE_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (-0x123456 == _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* signed big pack */ _dbus_pack_int32 (-0x123456, DBUS_BIG_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (-0x123456 == _dbus_unpack_int32 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned little */ _dbus_marshal_set_uint32 (&str, 0, 0x123456, DBUS_LITTLE_ENDIAN); _dbus_assert (0x123456 == _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned big */ _dbus_marshal_set_uint32 (&str, 0, 0x123456, DBUS_BIG_ENDIAN); _dbus_assert (0x123456 == _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned little pack */ _dbus_pack_uint32 (0x123456, DBUS_LITTLE_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (0x123456 == _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, _dbus_string_get_const_data (&str))); /* unsigned big pack */ _dbus_pack_uint32 (0x123456, DBUS_BIG_ENDIAN, _dbus_string_get_data (&str)); _dbus_assert (0x123456 == _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, _dbus_string_get_const_data (&str))); #endif /* set/pack tests for integers */ /* Strings in-place set */ byte_order = DBUS_LITTLE_ENDIAN; while (TRUE) { /* Init a string */ _dbus_string_set_length (&str, 0); /* reset pos for the macros */ pos = 0; MARSHAL_TEST_STRCMP (STRING, byte_order, "Hello world"); /* Set it to something longer */ _dbus_string_init_const (&t, "Hello world foo"); v_STRING = _dbus_string_get_const_data (&t); _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING, &v_STRING, byte_order, NULL, NULL); _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING, &v_STRING, byte_order, NULL); _dbus_assert (strcmp (v_STRING, "Hello world foo") == 0); /* Set it to something shorter */ _dbus_string_init_const (&t, "Hello"); v_STRING = _dbus_string_get_const_data (&t); _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING, &v_STRING, byte_order, NULL, NULL); _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING, &v_STRING, byte_order, NULL); _dbus_assert (strcmp (v_STRING, "Hello") == 0); /* Do the other byte order */ if (byte_order == DBUS_LITTLE_ENDIAN) byte_order = DBUS_BIG_ENDIAN; else break; } /* Clean up */ _dbus_string_free (&str); return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-list.h0000644000175000017500000001213312602773110015551 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-list.h Generic linked list utility (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_LIST_H #define DBUS_LIST_H #include #include #include #include DBUS_BEGIN_DECLS struct DBusList { DBusList *prev; /**< Previous list node. */ DBusList *next; /**< Next list node. */ void *data; /**< Data stored at this element. */ }; DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_append (DBusList **list, void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_prepend (DBusList **list, void *data); dbus_bool_t _dbus_list_insert_before (DBusList **list, DBusList *before_this_link, void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_insert_after (DBusList **list, DBusList *after_this_link, void *data); DBUS_PRIVATE_EXPORT void _dbus_list_insert_before_link (DBusList **list, DBusList *before_this_link, DBusList *link); DBUS_PRIVATE_EXPORT void _dbus_list_insert_after_link (DBusList **list, DBusList *after_this_link, DBusList *link); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_remove (DBusList **list, void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_remove_last (DBusList **list, void *data); DBUS_PRIVATE_EXPORT void _dbus_list_remove_link (DBusList **list, DBusList *link); DBUS_PRIVATE_EXPORT DBusList* _dbus_list_find_last (DBusList **list, void *data); DBUS_PRIVATE_EXPORT void _dbus_list_clear (DBusList **list); DBUS_PRIVATE_EXPORT DBusList* _dbus_list_get_first_link (DBusList **list); DBUS_PRIVATE_EXPORT DBusList* _dbus_list_get_last_link (DBusList **list); DBUS_PRIVATE_EXPORT void* _dbus_list_get_last (DBusList **list); DBUS_PRIVATE_EXPORT void* _dbus_list_get_first (DBusList **list); DBUS_PRIVATE_EXPORT void* _dbus_list_pop_first (DBusList **list); DBUS_PRIVATE_EXPORT void* _dbus_list_pop_last (DBusList **list); DBUS_PRIVATE_EXPORT DBusList* _dbus_list_pop_first_link (DBusList **list); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_copy (DBusList **list, DBusList **dest); DBUS_PRIVATE_EXPORT int _dbus_list_get_length (DBusList **list); DBUS_PRIVATE_EXPORT DBusList* _dbus_list_alloc_link (void *data); DBUS_PRIVATE_EXPORT void _dbus_list_free_link (DBusList *link); DBUS_PRIVATE_EXPORT void _dbus_list_unlink (DBusList **list, DBusList *link); DBUS_PRIVATE_EXPORT void _dbus_list_append_link (DBusList **list, DBusList *link); DBUS_PRIVATE_EXPORT void _dbus_list_prepend_link (DBusList **list, DBusList *link); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_list_length_is_one (DBusList **list); DBUS_PRIVATE_EXPORT void _dbus_list_foreach (DBusList **list, DBusForeachFunction function, void *data); #define _dbus_list_get_next_link(list, link) ((link)->next == *(list) ? NULL : (link)->next) #define _dbus_list_get_prev_link(list, link) ((link) == *(list) ? NULL : (link)->prev) /* if DBUS_ENABLE_STATS */ DBUS_PRIVATE_EXPORT void _dbus_list_get_stats (dbus_uint32_t *in_use_p, dbus_uint32_t *in_free_list_p, dbus_uint32_t *allocated_p); DBUS_END_DECLS #endif /* DBUS_LIST_H */ dbus-1.10.6/dbus/dbus-list.c0000644000175000017500000007203712602773110015555 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-list.c Generic linked list utility (internal to D-Bus implementation) * * Copyright (C) 2002 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-list.h" #include "dbus-mempool.h" #include "dbus-threads-internal.h" /** * @defgroup DBusList Linked list * @ingroup DBusInternals * @brief DBusList data structure * * Types and functions related to DBusList. */ /* Protected by _DBUS_LOCK (list) */ static DBusMemPool *list_pool; /** * @defgroup DBusListInternals Linked list implementation details * @ingroup DBusInternals * @brief DBusList implementation details * * The guts of DBusList. * * @{ */ /* the mem pool is probably a speed hit, with the thread * lock, though it does still save memory - unknown. */ static DBusList* alloc_link (void *data) { DBusList *link; if (!_DBUS_LOCK (list)) return FALSE; if (list_pool == NULL) { list_pool = _dbus_mem_pool_new (sizeof (DBusList), TRUE); if (list_pool == NULL) { _DBUS_UNLOCK (list); return NULL; } link = _dbus_mem_pool_alloc (list_pool); if (link == NULL) { _dbus_mem_pool_free (list_pool); list_pool = NULL; _DBUS_UNLOCK (list); return NULL; } } else { link = _dbus_mem_pool_alloc (list_pool); } if (link) link->data = data; _DBUS_UNLOCK (list); return link; } static void free_link (DBusList *link) { if (!_DBUS_LOCK (list)) _dbus_assert_not_reached ("we should have initialized global locks " "before we allocated a linked-list link"); if (_dbus_mem_pool_dealloc (list_pool, link)) { _dbus_mem_pool_free (list_pool); list_pool = NULL; } _DBUS_UNLOCK (list); } static void link_before (DBusList **list, DBusList *before_this_link, DBusList *link) { if (*list == NULL) { link->prev = link; link->next = link; *list = link; } else { link->next = before_this_link; link->prev = before_this_link->prev; before_this_link->prev = link; link->prev->next = link; if (before_this_link == *list) *list = link; } } static void link_after (DBusList **list, DBusList *after_this_link, DBusList *link) { if (*list == NULL) { link->prev = link; link->next = link; *list = link; } else { link->prev = after_this_link; link->next = after_this_link->next; after_this_link->next = link; link->next->prev = link; } } #ifdef DBUS_ENABLE_STATS void _dbus_list_get_stats (dbus_uint32_t *in_use_p, dbus_uint32_t *in_free_list_p, dbus_uint32_t *allocated_p) { if (!_DBUS_LOCK (list)) { *in_use_p = 0; *in_free_list_p = 0; *allocated_p = 0; return; } _dbus_mem_pool_get_stats (list_pool, in_use_p, in_free_list_p, allocated_p); _DBUS_UNLOCK (list); } #endif /** @} */ /** * @addtogroup DBusList * @{ */ /** * @struct DBusList * * A node in a linked list. * * DBusList is a circular list; that is, the tail of the list * points back to the head of the list. The empty list is * represented by a #NULL pointer. */ /** * @def _dbus_list_get_next_link * * Gets the next link in the list, or #NULL if * there are no more links. Used for iteration. * * @code * DBusList *link; * link = _dbus_list_get_first_link (&list); * while (link != NULL) * { * printf ("value is %p\n", link->data); * link = _dbus_list_get_next_link (&link); * } * @endcode * * @param list address of the list head. * @param link current link. * @returns the next link, or %NULL if none. * */ /** * @def _dbus_list_get_prev_link * * Gets the previous link in the list, or #NULL if * there are no more links. Used for iteration. * * @code * DBusList *link; * link = _dbus_list_get_last_link (&list); * while (link != NULL) * { * printf ("value is %p\n", link->data); * link = _dbus_list_get_prev_link (&link); * } * @endcode * * @param list address of the list head. * @param link current link. * @returns the previous link, or %NULL if none. * */ /** * Allocates a linked list node. Useful for preallocating * nodes and using _dbus_list_append_link() to avoid * allocations. * * @param data the value to store in the link. * @returns a newly allocated link. */ DBusList* _dbus_list_alloc_link (void *data) { return alloc_link (data); } /** * Frees a linked list node allocated with _dbus_list_alloc_link. * Does not free the data in the node. * * @param link the list node */ void _dbus_list_free_link (DBusList *link) { free_link (link); } /** * Appends a value to the list. May return #FALSE * if insufficient memory exists to add a list link. * This is a constant-time operation. * * @param list address of the list head. * @param data the value to append. * @returns #TRUE on success. */ dbus_bool_t _dbus_list_append (DBusList **list, void *data) { if (!_dbus_list_prepend (list, data)) return FALSE; /* Now cycle the list forward one so the prepended node is the tail */ *list = (*list)->next; return TRUE; } /** * Prepends a value to the list. May return #FALSE * if insufficient memory exists to add a list link. * This is a constant-time operation. * * @param list address of the list head. * @param data the value to prepend. * @returns #TRUE on success. */ dbus_bool_t _dbus_list_prepend (DBusList **list, void *data) { DBusList *link; link = alloc_link (data); if (link == NULL) return FALSE; link_before (list, *list, link); return TRUE; } /** * Appends a link to the list. * Cannot fail due to out of memory. * This is a constant-time operation. * * @param list address of the list head. * @param link the link to append. */ void _dbus_list_append_link (DBusList **list, DBusList *link) { _dbus_list_prepend_link (list, link); /* Now cycle the list forward one so the prepended node is the tail */ *list = (*list)->next; } /** * Prepends a link to the list. * Cannot fail due to out of memory. * This is a constant-time operation. * * @param list address of the list head. * @param link the link to prepend. */ void _dbus_list_prepend_link (DBusList **list, DBusList *link) { link_before (list, *list, link); } /** * Inserts data into the list after the given existing link. * * @param list the list to modify * @param after_this_link existing link to insert after, or #NULL to prepend * @param data the value to insert * @returns #TRUE on success, #FALSE if memory allocation fails */ dbus_bool_t _dbus_list_insert_after (DBusList **list, DBusList *after_this_link, void *data) { DBusList *link; if (after_this_link == NULL) return _dbus_list_prepend (list, data); else { link = alloc_link (data); if (link == NULL) return FALSE; link_after (list, after_this_link, link); } return TRUE; } /** * Inserts a link into the list before the given existing link. * * @param list the list to modify * @param before_this_link existing link to insert before, or #NULL to append * @param link the link to insert */ void _dbus_list_insert_before_link (DBusList **list, DBusList *before_this_link, DBusList *link) { if (before_this_link == NULL) _dbus_list_append_link (list, link); else link_before (list, before_this_link, link); } /** * Inserts a link into the list after the given existing link. * * @param list the list to modify * @param after_this_link existing link to insert after, or #NULL to prepend * @param link the link to insert */ void _dbus_list_insert_after_link (DBusList **list, DBusList *after_this_link, DBusList *link) { if (after_this_link == NULL) _dbus_list_prepend_link (list, link); else link_after (list, after_this_link, link); } /** * Removes a value from the list. Only removes the * first value equal to the given data pointer, * even if multiple values exist which match. * This is a linear-time operation. * * @param list address of the list head. * @param data the value to remove. * @returns #TRUE if a value was found to remove. */ dbus_bool_t _dbus_list_remove (DBusList **list, void *data) { DBusList *link; link = *list; while (link != NULL) { if (link->data == data) { _dbus_list_remove_link (list, link); return TRUE; } link = _dbus_list_get_next_link (list, link); } return FALSE; } /** * Removes a value from the list. Only removes the * last value equal to the given data pointer, * even if multiple values exist which match. * This is a linear-time operation. * * @param list address of the list head. * @param data the value to remove. * @returns #TRUE if a value was found to remove. */ dbus_bool_t _dbus_list_remove_last (DBusList **list, void *data) { DBusList *link; link = _dbus_list_find_last (list, data); if (link) { _dbus_list_remove_link (list, link); return TRUE; } else return FALSE; } /** * Finds a value in the list. Returns the last link * with value equal to the given data pointer. * This is a linear-time operation. * Returns #NULL if no value found that matches. * * @param list address of the list head. * @param data the value to find. * @returns the link if found */ DBusList* _dbus_list_find_last (DBusList **list, void *data) { DBusList *link; link = _dbus_list_get_last_link (list); while (link != NULL) { if (link->data == data) return link; link = _dbus_list_get_prev_link (list, link); } return NULL; } /** * Removes the given link from the list, but doesn't * free it. _dbus_list_remove_link() both removes the * link and also frees it. * * @param list the list * @param link the link in the list */ void _dbus_list_unlink (DBusList **list, DBusList *link) { if (link->next == link) { /* one-element list */ *list = NULL; } else { link->prev->next = link->next; link->next->prev = link->prev; if (*list == link) *list = link->next; } link->next = NULL; link->prev = NULL; } /** * Removes a link from the list. This is a constant-time operation. * * @param list address of the list head. * @param link the list link to remove. */ void _dbus_list_remove_link (DBusList **list, DBusList *link) { _dbus_list_unlink (list, link); free_link (link); } /** * Frees all links in the list and sets the list head to #NULL. Does * not free the data in each link, for obvious reasons. This is a * linear-time operation. * * @param list address of the list head. */ void _dbus_list_clear (DBusList **list) { DBusList *link; link = *list; while (link != NULL) { DBusList *next = _dbus_list_get_next_link (list, link); free_link (link); link = next; } *list = NULL; } /** * Gets the first link in the list. * This is a constant-time operation. * * @param list address of the list head. * @returns the first link, or #NULL for an empty list. */ DBusList* _dbus_list_get_first_link (DBusList **list) { return *list; } /** * Gets the last link in the list. * This is a constant-time operation. * * @param list address of the list head. * @returns the last link, or #NULL for an empty list. */ DBusList* _dbus_list_get_last_link (DBusList **list) { if (*list == NULL) return NULL; else return (*list)->prev; } /** * Gets the last data in the list. * This is a constant-time operation. * * @param list address of the list head. * @returns the last data in the list, or #NULL for an empty list. */ void* _dbus_list_get_last (DBusList **list) { if (*list == NULL) return NULL; else return (*list)->prev->data; } /** * Gets the first data in the list. * This is a constant-time operation. * * @param list address of the list head. * @returns the first data in the list, or #NULL for an empty list. */ void* _dbus_list_get_first (DBusList **list) { if (*list == NULL) return NULL; else return (*list)->data; } /** * Removes the first link in the list and returns it. This is a * constant-time operation. * * @param list address of the list head. * @returns the first link in the list, or #NULL for an empty list. */ DBusList* _dbus_list_pop_first_link (DBusList **list) { DBusList *link; link = _dbus_list_get_first_link (list); if (link == NULL) return NULL; _dbus_list_unlink (list, link); return link; } /** * Removes the first value in the list and returns it. This is a * constant-time operation. * * @param list address of the list head. * @returns the first data in the list, or #NULL for an empty list. */ void* _dbus_list_pop_first (DBusList **list) { DBusList *link; void *data; link = _dbus_list_get_first_link (list); if (link == NULL) return NULL; data = link->data; _dbus_list_remove_link (list, link); return data; } /** * Removes the last value in the list and returns it. This is a * constant-time operation. * * @param list address of the list head. * @returns the last data in the list, or #NULL for an empty list. */ void* _dbus_list_pop_last (DBusList **list) { DBusList *link; void *data; link = _dbus_list_get_last_link (list); if (link == NULL) return NULL; data = link->data; _dbus_list_remove_link (list, link); return data; } /** * Copies a list. This is a linear-time operation. If there isn't * enough memory to copy the entire list, the destination list will be * set to #NULL. * * @param list address of the head of the list to copy. * @param dest address where the copied list should be placed. * @returns #TRUE on success, #FALSE if not enough memory. */ dbus_bool_t _dbus_list_copy (DBusList **list, DBusList **dest) { DBusList *link; _dbus_assert (list != dest); *dest = NULL; link = *list; while (link != NULL) { if (!_dbus_list_append (dest, link->data)) { /* free what we have so far */ _dbus_list_clear (dest); return FALSE; } link = _dbus_list_get_next_link (list, link); } return TRUE; } /** * Gets the length of a list. This is a linear-time * operation. * * @param list address of the head of the list * @returns number of elements in the list. */ int _dbus_list_get_length (DBusList **list) { DBusList *link; int length; length = 0; link = *list; while (link != NULL) { ++length; link = _dbus_list_get_next_link (list, link); } return length; } /** * Calls the given function for each element in the list. The * function is passed the list element as its first argument, and the * given data as its second argument. * * @param list address of the head of the list. * @param function function to call for each element. * @param data extra data for the function. * */ void _dbus_list_foreach (DBusList **list, DBusForeachFunction function, void *data) { DBusList *link; link = *list; while (link != NULL) { DBusList *next = _dbus_list_get_next_link (list, link); (* function) (link->data, data); link = next; } } /** * Check whether length is exactly one. * * @param list the list * @returns #TRUE if length is exactly one */ dbus_bool_t _dbus_list_length_is_one (DBusList **list) { return (*list != NULL && (*list)->next == *list); } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include static void verify_list (DBusList **list) { DBusList *link; int length; link = *list; if (link == NULL) return; if (link->next == link) { _dbus_assert (link->prev == link); _dbus_assert (*list == link); return; } length = 0; do { length += 1; _dbus_assert (link->prev->next == link); _dbus_assert (link->next->prev == link); link = link->next; } while (link != *list); _dbus_assert (length == _dbus_list_get_length (list)); if (length == 1) _dbus_assert (_dbus_list_length_is_one (list)); else _dbus_assert (!_dbus_list_length_is_one (list)); } static dbus_bool_t is_ascending_sequence (DBusList **list) { DBusList *link; int prev; prev = _DBUS_INT_MIN; link = _dbus_list_get_first_link (list); while (link != NULL) { int v = _DBUS_POINTER_TO_INT (link->data); if (v <= prev) return FALSE; prev = v; link = _dbus_list_get_next_link (list, link); } return TRUE; } static dbus_bool_t is_descending_sequence (DBusList **list) { DBusList *link; int prev; prev = _DBUS_INT_MAX; link = _dbus_list_get_first_link (list); while (link != NULL) { int v = _DBUS_POINTER_TO_INT (link->data); if (v >= prev) return FALSE; prev = v; link = _dbus_list_get_next_link (list, link); } return TRUE; } static dbus_bool_t all_even_values (DBusList **list) { DBusList *link; link = _dbus_list_get_first_link (list); while (link != NULL) { int v = _DBUS_POINTER_TO_INT (link->data); if ((v % 2) != 0) return FALSE; link = _dbus_list_get_next_link (list, link); } return TRUE; } static dbus_bool_t all_odd_values (DBusList **list) { DBusList *link; link = _dbus_list_get_first_link (list); while (link != NULL) { int v = _DBUS_POINTER_TO_INT (link->data); if ((v % 2) == 0) return FALSE; link = _dbus_list_get_next_link (list, link); } return TRUE; } static dbus_bool_t lists_equal (DBusList **list1, DBusList **list2) { DBusList *link1; DBusList *link2; link1 = _dbus_list_get_first_link (list1); link2 = _dbus_list_get_first_link (list2); while (link1 && link2) { if (link1->data != link2->data) return FALSE; link1 = _dbus_list_get_next_link (list1, link1); link2 = _dbus_list_get_next_link (list2, link2); } if (link1 || link2) return FALSE; return TRUE; } /** * @ingroup DBusListInternals * Unit test for DBusList * @returns #TRUE on success. */ dbus_bool_t _dbus_list_test (void) { DBusList *list1; DBusList *list2; DBusList *link1; DBusList *link2; DBusList *copy1; DBusList *copy2; int i; list1 = NULL; list2 = NULL; /* Test append and prepend */ i = 0; while (i < 10) { if (!_dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("could not allocate for append"); if (!_dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("count not allocate for prepend"); ++i; verify_list (&list1); verify_list (&list2); _dbus_assert (_dbus_list_get_length (&list1) == i); _dbus_assert (_dbus_list_get_length (&list2) == i); } _dbus_assert (is_ascending_sequence (&list1)); _dbus_assert (is_descending_sequence (&list2)); /* Test list clear */ _dbus_list_clear (&list1); _dbus_list_clear (&list2); verify_list (&list1); verify_list (&list2); /* Test get_first, get_last, pop_first, pop_last */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } --i; while (i >= 0) { void *got_data1; void *got_data2; void *data1; void *data2; got_data1 = _dbus_list_get_last (&list1); got_data2 = _dbus_list_get_first (&list2); data1 = _dbus_list_pop_last (&list1); data2 = _dbus_list_pop_first (&list2); _dbus_assert (got_data1 == data1); _dbus_assert (got_data2 == data2); _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i); _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i); verify_list (&list1); verify_list (&list2); _dbus_assert (is_ascending_sequence (&list1)); _dbus_assert (is_descending_sequence (&list2)); --i; } _dbus_assert (list1 == NULL); _dbus_assert (list2 == NULL); /* Test get_first_link, get_last_link, pop_first_link, pop_last_link */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } --i; while (i >= 0) { DBusList *got_link1; DBusList *got_link2; DBusList *link2; void *data1_indirect; void *data1; void *data2; got_link1 = _dbus_list_get_last_link (&list1); got_link2 = _dbus_list_get_first_link (&list2); link2 = _dbus_list_pop_first_link (&list2); _dbus_assert (got_link2 == link2); data1_indirect = got_link1->data; /* this call makes got_link1 invalid */ data1 = _dbus_list_pop_last (&list1); _dbus_assert (data1 == data1_indirect); data2 = link2->data; _dbus_list_free_link (link2); _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i); _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i); verify_list (&list1); verify_list (&list2); _dbus_assert (is_ascending_sequence (&list1)); _dbus_assert (is_descending_sequence (&list2)); --i; } _dbus_assert (list1 == NULL); _dbus_assert (list2 == NULL); /* Test iteration */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; verify_list (&list1); verify_list (&list2); _dbus_assert (_dbus_list_get_length (&list1) == i); _dbus_assert (_dbus_list_get_length (&list2) == i); } _dbus_assert (is_ascending_sequence (&list1)); _dbus_assert (is_descending_sequence (&list2)); --i; link2 = _dbus_list_get_first_link (&list2); while (link2 != NULL) { verify_list (&link2); /* pretend this link is the head */ _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i); link2 = _dbus_list_get_next_link (&list2, link2); --i; } i = 0; link1 = _dbus_list_get_first_link (&list1); while (link1 != NULL) { verify_list (&link1); /* pretend this link is the head */ _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); link1 = _dbus_list_get_next_link (&list1, link1); ++i; } --i; link1 = _dbus_list_get_last_link (&list1); while (link1 != NULL) { verify_list (&link1); /* pretend this link is the head */ _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); link1 = _dbus_list_get_prev_link (&list1, link1); --i; } _dbus_list_clear (&list1); _dbus_list_clear (&list2); /* Test remove */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } --i; while (i >= 0) { if ((i % 2) == 0) { if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("element should have been in list"); if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("element should have been in list"); verify_list (&list1); verify_list (&list2); } --i; } _dbus_assert (all_odd_values (&list1)); _dbus_assert (all_odd_values (&list2)); _dbus_list_clear (&list1); _dbus_list_clear (&list2); /* test removing the other half of the elements */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } --i; while (i >= 0) { if ((i % 2) != 0) { if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("element should have been in list"); if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i))) _dbus_assert_not_reached ("element should have been in list"); verify_list (&list1); verify_list (&list2); } --i; } _dbus_assert (all_even_values (&list1)); _dbus_assert (all_even_values (&list2)); /* clear list using remove_link */ while (list1 != NULL) { _dbus_list_remove_link (&list1, list1); verify_list (&list1); } while (list2 != NULL) { _dbus_list_remove_link (&list2, list2); verify_list (&list2); } /* Test remove link more generally */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } --i; link2 = _dbus_list_get_first_link (&list2); while (link2 != NULL) { DBusList *next = _dbus_list_get_next_link (&list2, link2); _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i); if ((i % 2) == 0) _dbus_list_remove_link (&list2, link2); verify_list (&list2); link2 = next; --i; } _dbus_assert (all_odd_values (&list2)); _dbus_list_clear (&list2); i = 0; link1 = _dbus_list_get_first_link (&list1); while (link1 != NULL) { DBusList *next = _dbus_list_get_next_link (&list1, link1); _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); if ((i % 2) != 0) _dbus_list_remove_link (&list1, link1); verify_list (&list1); link1 = next; ++i; } _dbus_assert (all_even_values (&list1)); _dbus_list_clear (&list1); /* Test copying a list */ i = 0; while (i < 10) { _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); ++i; } /* bad pointers, because they are allowed in the copy dest */ copy1 = _DBUS_INT_TO_POINTER (0x342234); copy2 = _DBUS_INT_TO_POINTER (23); _dbus_list_copy (&list1, ©1); verify_list (&list1); verify_list (©1); _dbus_assert (lists_equal (&list1, ©1)); _dbus_list_copy (&list2, ©2); verify_list (&list2); verify_list (©2); _dbus_assert (lists_equal (&list2, ©2)); /* Now test copying empty lists */ _dbus_list_clear (&list1); _dbus_list_clear (&list2); _dbus_list_clear (©1); _dbus_list_clear (©2); /* bad pointers, because they are allowed in the copy dest */ copy1 = _DBUS_INT_TO_POINTER (0x342234); copy2 = _DBUS_INT_TO_POINTER (23); _dbus_list_copy (&list1, ©1); verify_list (&list1); verify_list (©1); _dbus_assert (lists_equal (&list1, ©1)); _dbus_list_copy (&list2, ©2); verify_list (&list2); verify_list (©2); _dbus_assert (lists_equal (&list2, ©2)); _dbus_list_clear (&list1); _dbus_list_clear (&list2); /* insert_after on empty list */ _dbus_list_insert_after (&list1, NULL, _DBUS_INT_TO_POINTER (0)); verify_list (&list1); /* inserting after first element */ _dbus_list_insert_after (&list1, list1, _DBUS_INT_TO_POINTER (1)); verify_list (&list1); _dbus_assert (is_ascending_sequence (&list1)); /* inserting at the end */ _dbus_list_insert_after (&list1, list1->next, _DBUS_INT_TO_POINTER (2)); verify_list (&list1); _dbus_assert (is_ascending_sequence (&list1)); /* using insert_after to prepend */ _dbus_list_insert_after (&list1, NULL, _DBUS_INT_TO_POINTER (-1)); verify_list (&list1); _dbus_assert (is_ascending_sequence (&list1)); _dbus_list_clear (&list1); /* using remove_last */ _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (2)); _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (1)); _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (3)); _dbus_list_remove_last (&list1, _DBUS_INT_TO_POINTER (2)); verify_list (&list1); _dbus_assert (is_ascending_sequence (&list1)); _dbus_list_clear (&list1); return TRUE; } #endif dbus-1.10.6/dbus/dbus-internals.h0000644000175000017500000003733412602773110016607 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-internals.h random utility stuff (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef DBUS_INSIDE_DBUS_H #error "You can't include dbus-internals.h in the public header dbus.h" #endif #ifndef DBUS_INTERNALS_H #define DBUS_INTERNALS_H #include #include #include #include #include DBUS_BEGIN_DECLS DBUS_PRIVATE_EXPORT void _dbus_warn (const char *format, ...) _DBUS_GNUC_PRINTF (1, 2); DBUS_PRIVATE_EXPORT void _dbus_warn_check_failed (const char *format, ...) _DBUS_GNUC_PRINTF (1, 2); #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #define _DBUS_FUNCTION_NAME __func__ #elif defined(__GNUC__) || defined(_MSC_VER) #define _DBUS_FUNCTION_NAME __FUNCTION__ #else #define _DBUS_FUNCTION_NAME "unknown function" #endif /* * (code from GLib) * * The _DBUS_LIKELY and _DBUS_UNLIKELY macros let the programmer give hints to * the compiler about the expected result of an expression. Some compilers * can use this information for optimizations. * * The _DBUS_BOOLEAN_EXPR macro is intended to trigger a gcc warning when * putting assignments in the macro arg */ #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) #define _DBUS_BOOLEAN_EXPR(expr) \ __extension__ ({ \ int _dbus_boolean_var_; \ if (expr) \ _dbus_boolean_var_ = 1; \ else \ _dbus_boolean_var_ = 0; \ _dbus_boolean_var_; \ }) #define _DBUS_LIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 1)) #define _DBUS_UNLIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 0)) #else #define _DBUS_LIKELY(expr) (expr) #define _DBUS_UNLIKELY(expr) (expr) #endif #ifdef DBUS_ENABLE_VERBOSE_MODE /* at least gnu cc and msvc compiler are known to have support for variable macro argument lists add other compilers is required */ #if defined(__GNUC__) || defined(_MSC_VER) #define DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS #endif #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS DBUS_PRIVATE_EXPORT void _dbus_verbose_real (const char *file, const int line, const char *function, const char *format,...) _DBUS_GNUC_PRINTF (4, 5); # define _dbus_verbose(fmt,...) _dbus_verbose_real( __FILE__,__LINE__,__FUNCTION__,fmt, ## __VA_ARGS__) #else DBUS_PRIVATE_EXPORT void _dbus_verbose_real (const char *format, ...) _DBUS_GNUC_PRINTF (1, 2); # define _dbus_verbose _dbus_verbose_real #endif DBUS_PRIVATE_EXPORT void _dbus_verbose_reset_real (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_is_verbose_real (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_get_verbose (void); DBUS_PRIVATE_EXPORT void _dbus_set_verbose (dbus_bool_t state); # define _dbus_verbose_reset _dbus_verbose_reset_real # define _dbus_is_verbose _dbus_is_verbose_real #else # ifdef HAVE_ISO_VARARGS # define _dbus_verbose(...) do { } while (0) # elif defined (HAVE_GNUC_VARARGS) # define _dbus_verbose(format...) do { } while (0) # else static void _dbus_verbose(const char * x,...) {;} # endif # define _dbus_verbose_reset() do { } while (0) # define _dbus_is_verbose() FALSE #endif /* !DBUS_ENABLE_VERBOSE_MODE */ void _dbus_trace_ref (const char *obj_name, void *obj, int old_refcount, int new_refcount, const char *why, const char *env_var, int *enabled); DBUS_PRIVATE_EXPORT const char* _dbus_strerror (int error_number); #ifdef DBUS_DISABLE_ASSERT #define _dbus_assert(condition) do { } while (0) #else DBUS_PRIVATE_EXPORT void _dbus_real_assert (dbus_bool_t condition, const char *condition_text, const char *file, int line, const char *func); #define _dbus_assert(condition) \ _dbus_real_assert ((condition) != 0, #condition, __FILE__, __LINE__, _DBUS_FUNCTION_NAME) #endif /* !DBUS_DISABLE_ASSERT */ #ifdef DBUS_DISABLE_ASSERT #define _dbus_assert_not_reached(explanation) do { } while (0) #else DBUS_PRIVATE_EXPORT void _dbus_real_assert_not_reached (const char *explanation, const char *file, int line) _DBUS_GNUC_NORETURN; #define _dbus_assert_not_reached(explanation) \ _dbus_real_assert_not_reached (explanation, __FILE__, __LINE__) #endif /* !DBUS_DISABLE_ASSERT */ #ifdef DBUS_DISABLE_CHECKS #define _dbus_return_if_fail(condition) #define _dbus_return_val_if_fail(condition, val) #else DBUS_PRIVATE_EXPORT extern const char *_dbus_return_if_fail_warning_format; #define _dbus_return_if_fail(condition) do { \ _dbus_assert ((*(const char*)_DBUS_FUNCTION_NAME) != '_'); \ if (!(condition)) { \ _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, \ _DBUS_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ return; \ } } while (0) #define _dbus_return_val_if_fail(condition, val) do { \ _dbus_assert ((*(const char*)_DBUS_FUNCTION_NAME) != '_'); \ if (!(condition)) { \ _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, \ _DBUS_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ return (val); \ } } while (0) #endif /* !DBUS_DISABLE_ASSERT */ #define _DBUS_N_ELEMENTS(array) ((int) (sizeof ((array)) / sizeof ((array)[0]))) #define _DBUS_POINTER_TO_INT(pointer) ((intptr_t)(pointer)) #define _DBUS_INT_TO_POINTER(integer) ((void*)((intptr_t)(integer))) #define _DBUS_ZERO(object) (memset (&(object), '\0', sizeof ((object)))) #define _DBUS_STRUCT_OFFSET(struct_type, member) \ ((intptr_t) ((unsigned char*) &((struct_type*) 0)->member)) #ifdef DBUS_DISABLE_CHECKS /* this is an assert and not an error, but in the typical --disable-checks case (you're trying * to really minimize code size), disabling these assertions makes sense. */ #define _DBUS_ASSERT_ERROR_IS_SET(error) do { } while (0) #define _DBUS_ASSERT_ERROR_IS_CLEAR(error) do { } while (0) #else static inline void _dbus_assert_error_is_set (const DBusError *error) { _dbus_assert (error == NULL || dbus_error_is_set (error)); } static inline void _dbus_assert_error_is_clear (const DBusError *error) { _dbus_assert (error == NULL || !dbus_error_is_set (error)); } #define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert_error_is_set(error) #define _DBUS_ASSERT_ERROR_IS_CLEAR(error) _dbus_assert_error_is_clear(error) #endif #define _dbus_return_if_error_is_set(error) _dbus_return_if_fail ((error) == NULL || !dbus_error_is_set ((error))) #define _dbus_return_val_if_error_is_set(error, val) _dbus_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), (val)) /* This alignment thing is from ORBit2 */ /* Align a value upward to a boundary, expressed as a number of bytes. * E.g. align to an 8-byte boundary with argument of 8. */ /* * (this + boundary - 1) * & * ~(boundary - 1) */ #define _DBUS_ALIGN_VALUE(this, boundary) \ (( ((uintptr_t)(this)) + (((uintptr_t)(boundary)) -1)) & (~(((uintptr_t)(boundary))-1))) #define _DBUS_ALIGN_ADDRESS(this, boundary) \ ((void*)_DBUS_ALIGN_VALUE(this, boundary)) DBUS_PRIVATE_EXPORT char* _dbus_strdup (const char *str); void* _dbus_memdup (const void *mem, size_t n_bytes); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_string_array_contains (const char **array, const char *str); char** _dbus_dup_string_array (const char **array); #define _DBUS_INT16_MIN ((dbus_int16_t) 0x8000) #define _DBUS_INT16_MAX ((dbus_int16_t) 0x7fff) #define _DBUS_UINT16_MAX ((dbus_uint16_t)0xffff) #define _DBUS_INT32_MIN ((dbus_int32_t) 0x80000000) #define _DBUS_INT32_MAX ((dbus_int32_t) 0x7fffffff) #define _DBUS_UINT32_MAX ((dbus_uint32_t)0xffffffff) /* using 32-bit here is sort of bogus */ #define _DBUS_INT_MIN _DBUS_INT32_MIN #define _DBUS_INT_MAX _DBUS_INT32_MAX #define _DBUS_UINT_MAX _DBUS_UINT32_MAX #define _DBUS_INT64_MAX DBUS_INT64_CONSTANT (0x7fffffffffffffff) #define _DBUS_UINT64_MAX DBUS_UINT64_CONSTANT (0xffffffffffffffff) #define _DBUS_ONE_KILOBYTE 1024 #define _DBUS_ONE_MEGABYTE 1024 * _DBUS_ONE_KILOBYTE #define _DBUS_ONE_HOUR_IN_MILLISECONDS (1000 * 60 * 60) #define _DBUS_USEC_PER_SECOND (1000000) #undef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #undef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #undef ABS #define ABS(a) (((a) < 0) ? -(a) : (a)) #define _DBUS_ISASCII(c) ((c) != '\0' && (((c) & ~0x7f) == 0)) typedef void (* DBusForeachFunction) (void *element, void *data); void _dbus_verbose_bytes (const unsigned char *data, int len, int offset); DBUS_PRIVATE_EXPORT void _dbus_verbose_bytes_of_string (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT extern const char *_dbus_no_memory_message; #define _DBUS_SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message) DBUS_PRIVATE_EXPORT void _dbus_set_error_valist (DBusError *error, const char *name, const char *format, va_list args) _DBUS_GNUC_PRINTF (3, 0); #ifdef DBUS_ENABLE_EMBEDDED_TESTS /* Memory debugging */ void _dbus_set_fail_alloc_counter (int until_next_fail); int _dbus_get_fail_alloc_counter (void); void _dbus_set_fail_alloc_failures (int failures_per_failure); int _dbus_get_fail_alloc_failures (void); dbus_bool_t _dbus_decrement_fail_alloc_counter (void); dbus_bool_t _dbus_disable_mem_pools (void); DBUS_PRIVATE_EXPORT int _dbus_get_malloc_blocks_outstanding (void); typedef dbus_bool_t (* DBusTestMemoryFunction) (void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_test_oom_handling (const char *description, DBusTestMemoryFunction func, void *data); #else #define _dbus_set_fail_alloc_counter(n) #define _dbus_get_fail_alloc_counter _DBUS_INT_MAX /* These are constant expressions so that blocks * they protect should be optimized away */ #define _dbus_decrement_fail_alloc_counter() (FALSE) #define _dbus_disable_mem_pools() (FALSE) #define _dbus_get_malloc_blocks_outstanding (0) #endif /* !DBUS_ENABLE_EMBEDDED_TESTS */ typedef void (* DBusShutdownFunction) (void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction function, void *data); dbus_bool_t _dbus_register_shutdown_func_unlocked (DBusShutdownFunction function, void *data); extern int _dbus_current_generation; /* The weird case convention is to avoid having to change all the callers, * which would be quite a mega-patch. */ typedef enum { /* index 0-4 */ _DBUS_LOCK_list, _DBUS_LOCK_connection_slots, _DBUS_LOCK_pending_call_slots, _DBUS_LOCK_server_slots, _DBUS_LOCK_message_slots, /* index 5-9 */ _DBUS_LOCK_bus, _DBUS_LOCK_bus_datas, _DBUS_LOCK_shutdown_funcs, _DBUS_LOCK_system_users, _DBUS_LOCK_message_cache, /* index 10-12 */ _DBUS_LOCK_shared_connections, _DBUS_LOCK_machine_uuid, _DBUS_LOCK_sysdeps, _DBUS_N_GLOBAL_LOCKS } DBusGlobalLock; dbus_bool_t _dbus_lock (DBusGlobalLock lock) _DBUS_GNUC_WARN_UNUSED_RESULT; void _dbus_unlock (DBusGlobalLock lock); #define _DBUS_LOCK_NAME(name) _DBUS_LOCK_##name #define _DBUS_LOCK(name) _dbus_lock (_DBUS_LOCK_##name) #define _DBUS_UNLOCK(name) _dbus_unlock (_DBUS_LOCK_##name) DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_threads_init_debug (void); dbus_bool_t _dbus_address_append_escaped (DBusString *escaped, const DBusString *unescaped); void _dbus_set_bad_address (DBusError *error, const char *address_problem_type, const char *address_problem_field, const char *address_problem_other); #define DBUS_UUID_LENGTH_BYTES 16 #define DBUS_UUID_LENGTH_WORDS (DBUS_UUID_LENGTH_BYTES / 4) #define DBUS_UUID_LENGTH_HEX (DBUS_UUID_LENGTH_BYTES * 2) /** * A globally unique ID ; we have one for each DBusServer, and also one for each * machine with libdbus installed on it. */ union DBusGUID { dbus_uint32_t as_uint32s[DBUS_UUID_LENGTH_WORDS]; /**< guid as four uint32 values */ char as_bytes[DBUS_UUID_LENGTH_BYTES]; /**< guid as 16 single-byte values */ }; DBUS_PRIVATE_EXPORT _DBUS_GNUC_WARN_UNUSED_RESULT dbus_bool_t _dbus_generate_uuid (DBusGUID *uuid, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_uuid_encode (const DBusGUID *uuid, DBusString *encoded); dbus_bool_t _dbus_read_uuid_file (const DBusString *filename, DBusGUID *uuid, dbus_bool_t create_if_not_found, DBusError *error); dbus_bool_t _dbus_write_uuid_file (const DBusString *filename, const DBusGUID *uuid, DBusError *error); dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str, DBusError *error); #define _DBUS_PASTE2(a, b) a ## b #define _DBUS_PASTE(a, b) _DBUS_PASTE2 (a, b) #define _DBUS_STATIC_ASSERT(expr) \ typedef struct { char _assertion[(expr) ? 1 : -1]; } \ _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__) _DBUS_GNUC_UNUSED DBUS_END_DECLS #endif /* DBUS_INTERNALS_H */ dbus-1.10.6/dbus/dbus-internals.c0000644000175000017500000006464012627362053016611 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-internals.c random utility stuff (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-protocol.h" #include "dbus-marshal-basic.h" #include "dbus-test.h" #include "dbus-valgrind-internal.h" #include #include #include #include #ifdef DBUS_USE_OUTPUT_DEBUG_STRING #include #include #endif /** * @defgroup DBusInternals D-Bus secret internal implementation details * @brief Documentation useful when developing or debugging D-Bus itself. * */ /** * @defgroup DBusInternalsUtils Utilities and portability * @ingroup DBusInternals * @brief Utility functions (_dbus_assert(), _dbus_warn(), etc.) * @{ */ /** * @def _dbus_assert * * Aborts with an error message if the condition is false. * * @param condition condition which must be true. */ /** * @def _dbus_assert_not_reached * * Aborts with an error message if called. * The given explanation will be printed. * * @param explanation explanation of what happened if the code was reached. */ /** * @def _DBUS_N_ELEMENTS * * Computes the number of elements in a fixed-size array using * sizeof(). * * @param array the array to count elements in. */ /** * @def _DBUS_POINTER_TO_INT * * Safely casts a void* to an integer; should only be used on void* * that actually contain integers, for example one created with * _DBUS_INT_TO_POINTER. Only guaranteed to preserve 32 bits. * (i.e. it's used to store 32-bit ints in pointers, but * can't be used to store 64-bit pointers in ints.) * * @param pointer pointer to extract an integer from. */ /** * @def _DBUS_INT_TO_POINTER * * Safely stuffs an integer into a pointer, to be extracted later with * _DBUS_POINTER_TO_INT. Only guaranteed to preserve 32 bits. * * @param integer the integer to stuff into a pointer. */ /** * @def _DBUS_ZERO * * Sets all bits in an object to zero. * * @param object the object to be zeroed. */ /** * @def _DBUS_INT16_MIN * * Minimum value of type "int16" */ /** * @def _DBUS_INT16_MAX * * Maximum value of type "int16" */ /** * @def _DBUS_UINT16_MAX * * Maximum value of type "uint16" */ /** * @def _DBUS_INT32_MIN * * Minimum value of type "int32" */ /** * @def _DBUS_INT32_MAX * * Maximum value of type "int32" */ /** * @def _DBUS_UINT32_MAX * * Maximum value of type "uint32" */ /** * @def _DBUS_INT_MIN * * Minimum value of type "int" */ /** * @def _DBUS_INT_MAX * * Maximum value of type "int" */ /** * @def _DBUS_UINT_MAX * * Maximum value of type "uint" */ /** * @typedef DBusForeachFunction * * Used to iterate over each item in a collection, such as * a DBusList. */ /** * @def _DBUS_LOCK_NAME * * Expands to name of a global lock variable. */ /** * @def _DBUS_LOCK * * Locks a global lock, initializing it first if necessary. * * @returns #FALSE if not enough memory */ /** * @def _DBUS_UNLOCK * * Unlocks a global lock */ /** * Fixed "out of memory" error message, just to avoid * making up a different string every time and wasting * space. */ const char *_dbus_no_memory_message = "Not enough memory"; static dbus_bool_t warn_initted = FALSE; static dbus_bool_t fatal_warnings = FALSE; static dbus_bool_t fatal_warnings_on_check_failed = TRUE; static void init_warnings(void) { if (!warn_initted) { const char *s; s = _dbus_getenv ("DBUS_FATAL_WARNINGS"); if (s && *s) { if (*s == '0') { fatal_warnings = FALSE; fatal_warnings_on_check_failed = FALSE; } else if (*s == '1') { fatal_warnings = TRUE; fatal_warnings_on_check_failed = TRUE; } else { fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'", s); } } warn_initted = TRUE; } } /** * Prints a warning message to stderr. Can optionally be made to exit * fatally by setting DBUS_FATAL_WARNINGS, but this is rarely * used. This function should be considered pretty much equivalent to * fprintf(stderr). _dbus_warn_check_failed() on the other hand is * suitable for use when a programming mistake has been made. * * @param format printf-style format string. */ void _dbus_warn (const char *format, ...) { va_list args; if (!warn_initted) init_warnings (); va_start (args, format); vfprintf (stderr, format, args); va_end (args); if (fatal_warnings) { fflush (stderr); _dbus_abort (); } } /** * Prints a "critical" warning to stderr when an assertion fails; * differs from _dbus_warn primarily in that it prefixes the pid and * defaults to fatal. This should be used only when a programming * error has been detected. (NOT for unavoidable errors that an app * might handle - those should be returned as DBusError.) Calling this * means "there is a bug" */ void _dbus_warn_check_failed(const char *format, ...) { va_list args; if (!warn_initted) init_warnings (); fprintf (stderr, "process %lu: ", _dbus_pid_for_log ()); va_start (args, format); vfprintf (stderr, format, args); va_end (args); if (fatal_warnings_on_check_failed) { fflush (stderr); _dbus_abort (); } } #ifdef DBUS_ENABLE_VERBOSE_MODE static dbus_bool_t verbose_initted = FALSE; static dbus_bool_t verbose = TRUE; /** Whether to show the current thread in verbose messages */ #define PTHREAD_IN_VERBOSE 0 #if PTHREAD_IN_VERBOSE #include #endif #ifdef DBUS_USE_OUTPUT_DEBUG_STRING static char module_name[1024]; #endif static inline void _dbus_verbose_init (void) { if (!verbose_initted) { const char *p = _dbus_getenv ("DBUS_VERBOSE"); verbose = p != NULL && *p == '1'; verbose_initted = TRUE; #ifdef DBUS_USE_OUTPUT_DEBUG_STRING { char *last_period, *last_slash; GetModuleFileName(0,module_name,sizeof(module_name)-1); last_period = _mbsrchr(module_name,'.'); if (last_period) *last_period ='\0'; last_slash = _mbsrchr(module_name,'\\'); if (last_slash) strcpy(module_name,last_slash+1); strcat(module_name,": "); } #endif } } /** @def DBUS_IS_DIR_SEPARATOR(c) * macro for checking if character c is a patch separator * * @todo move to a header file so that others can use this too */ #ifdef DBUS_WIN #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/') #else #define DBUS_IS_DIR_SEPARATOR(c) (c == '/') #endif /** remove source root from file path the source root is determined by */ static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level) { int prefix = 0; char *p = (char *)file + strlen(file); int i = 0; for (;p >= file;p--) { if (DBUS_IS_DIR_SEPARATOR(*p)) { if (++i >= level) { prefix = p-file+1; break; } } } return (char *)file+prefix; } /** * Implementation of dbus_is_verbose() macro if built with verbose logging * enabled. * @returns whether verbose logging is active. */ dbus_bool_t _dbus_is_verbose_real (void) { _dbus_verbose_init (); return verbose; } void _dbus_set_verbose (dbus_bool_t state) { verbose = state; } dbus_bool_t _dbus_get_verbose (void) { return verbose; } /** * Prints a warning message to stderr * if the user has enabled verbose mode. * This is the real function implementation, * use _dbus_verbose() macro in code. * * @param format printf-style format string. */ void _dbus_verbose_real ( #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS const char *file, const int line, const char *function, #endif const char *format, ...) { va_list args; static dbus_bool_t need_pid = TRUE; int len; /* things are written a bit oddly here so that * in the non-verbose case we just have the one * conditional and return immediately. */ if (!_dbus_is_verbose_real()) return; #ifndef DBUS_USE_OUTPUT_DEBUG_STRING /* Print out pid before the line */ if (need_pid) { #if PTHREAD_IN_VERBOSE fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ()); #else fprintf (stderr, "%lu: ", _dbus_pid_for_log ()); #endif } #endif /* Only print pid again if the next line is a new line */ len = strlen (format); if (format[len-1] == '\n') need_pid = TRUE; else need_pid = FALSE; va_start (args, format); #ifdef DBUS_USE_OUTPUT_DEBUG_STRING { char buf[1024]; strcpy(buf,module_name); #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function); #endif vsprintf (buf+strlen(buf),format, args); va_end (args); OutputDebugStringA(buf); } #else #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function); #endif vfprintf (stderr, format, args); va_end (args); fflush (stderr); #endif } /** * Reinitializes the verbose logging code, used * as a hack in dbus-spawn.c so that a child * process re-reads its pid * */ void _dbus_verbose_reset_real (void) { verbose_initted = FALSE; } void _dbus_trace_ref (const char *obj_name, void *obj, int old_refcount, int new_refcount, const char *why, const char *env_var, int *enabled) { _dbus_assert (obj_name != NULL); _dbus_assert (obj != NULL); _dbus_assert (old_refcount >= -1); _dbus_assert (new_refcount >= -1); if (old_refcount == -1) { _dbus_assert (new_refcount == -1); } else { _dbus_assert (new_refcount >= 0); _dbus_assert (old_refcount >= 0); _dbus_assert (old_refcount > 0 || new_refcount > 0); } _dbus_assert (why != NULL); _dbus_assert (env_var != NULL); _dbus_assert (enabled != NULL); if (*enabled < 0) { const char *s = _dbus_getenv (env_var); *enabled = FALSE; if (s && *s) { if (*s == '0') *enabled = FALSE; else if (*s == '1') *enabled = TRUE; else _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s); } } if (*enabled) { if (old_refcount == -1) { VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)", obj_name, obj, why); _dbus_verbose ("%s %p ref stolen (%s)\n", obj_name, obj, why); } else { VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)", obj_name, obj, old_refcount, new_refcount, why); _dbus_verbose ("%s %p %d -> %d refs (%s)\n", obj_name, obj, old_refcount, new_refcount, why); } } } #endif /* DBUS_ENABLE_VERBOSE_MODE */ /** * Duplicates a string. Result must be freed with * dbus_free(). Returns #NULL if memory allocation fails. * If the string to be duplicated is #NULL, returns #NULL. * * @param str string to duplicate. * @returns newly-allocated copy. */ char* _dbus_strdup (const char *str) { size_t len; char *copy; if (str == NULL) return NULL; len = strlen (str); copy = dbus_malloc (len + 1); if (copy == NULL) return NULL; memcpy (copy, str, len + 1); return copy; } /** * Duplicates a block of memory. Returns * #NULL on failure. * * @param mem memory to copy * @param n_bytes number of bytes to copy * @returns the copy */ void* _dbus_memdup (const void *mem, size_t n_bytes) { void *copy; copy = dbus_malloc (n_bytes); if (copy == NULL) return NULL; memcpy (copy, mem, n_bytes); return copy; } /** * Duplicates a string array. Result may be freed with * dbus_free_string_array(). Returns #NULL if memory allocation fails. * If the array to be duplicated is #NULL, returns #NULL. * * @param array array to duplicate. * @returns newly-allocated copy. */ char** _dbus_dup_string_array (const char **array) { int len; int i; char **copy; if (array == NULL) return NULL; for (len = 0; array[len] != NULL; ++len) ; copy = dbus_new0 (char*, len + 1); if (copy == NULL) return NULL; i = 0; while (i < len) { copy[i] = _dbus_strdup (array[i]); if (copy[i] == NULL) { dbus_free_string_array (copy); return NULL; } ++i; } return copy; } /** * Checks whether a string array contains the given string. * * @param array array to search. * @param str string to look for * @returns #TRUE if array contains string */ dbus_bool_t _dbus_string_array_contains (const char **array, const char *str) { int i; i = 0; while (array[i] != NULL) { if (strcmp (array[i], str) == 0) return TRUE; ++i; } return FALSE; } /** * Generates a new UUID. If you change how this is done, * there's some text about it in the spec that should also change. * * @param uuid the uuid to initialize * @param error location to store reason for failure * @returns #TRUE on success */ dbus_bool_t _dbus_generate_uuid (DBusGUID *uuid, DBusError *error) { DBusError rand_error; long now; dbus_error_init (&rand_error); /* don't use monotonic time because the UUID may be saved to disk, e.g. * it may persist across reboots */ _dbus_get_real_time (&now, NULL); uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now); if (!_dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4, &rand_error)) { dbus_set_error (error, rand_error.name, "Failed to generate UUID: %s", rand_error.message); dbus_error_free (&rand_error); return FALSE; } return TRUE; } /** * Hex-encode a UUID. * * @param uuid the uuid * @param encoded string to append hex uuid to * @returns #FALSE if no memory */ dbus_bool_t _dbus_uuid_encode (const DBusGUID *uuid, DBusString *encoded) { DBusString binary; _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded)); } static dbus_bool_t _dbus_read_uuid_file_without_creating (const DBusString *filename, DBusGUID *uuid, DBusError *error) { DBusString contents; DBusString decoded; int end; if (!_dbus_string_init (&contents)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_string_init (&decoded)) { _dbus_string_free (&contents); _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_file_get_contents (&contents, filename, error)) goto error; _dbus_string_chop_white (&contents); if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX) { dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text", _dbus_string_get_const_data (filename), DBUS_UUID_LENGTH_HEX, _dbus_string_get_length (&contents)); goto error; } if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0)) { _DBUS_SET_OOM (error); goto error; } if (end == 0) { dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, "UUID file '%s' contains invalid hex data", _dbus_string_get_const_data (filename)); goto error; } if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES) { dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, "UUID file '%s' contains %d bytes of hex-encoded data instead of %d", _dbus_string_get_const_data (filename), _dbus_string_get_length (&decoded), DBUS_UUID_LENGTH_BYTES); goto error; } _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); _dbus_string_free (&decoded); _dbus_string_free (&contents); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; error: _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&contents); _dbus_string_free (&decoded); return FALSE; } /** * Write the give UUID to a file. * * @param filename the file to write * @param uuid the UUID to save * @param error used to raise an error * @returns #FALSE on error */ dbus_bool_t _dbus_write_uuid_file (const DBusString *filename, const DBusGUID *uuid, DBusError *error) { DBusString encoded; if (!_dbus_string_init (&encoded)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_uuid_encode (uuid, &encoded)) { _DBUS_SET_OOM (error); goto error; } if (!_dbus_string_append_byte (&encoded, '\n')) { _DBUS_SET_OOM (error); goto error; } if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error)) goto error; _dbus_string_free (&encoded); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; error: _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&encoded); return FALSE; } /** * Reads (and optionally writes) a uuid to a file. Initializes the uuid * unless an error is returned. * * @param filename the name of the file * @param uuid uuid to be initialized with the loaded uuid * @param create_if_not_found #TRUE to create a new uuid and save it if the file doesn't exist * @param error the error return * @returns #FALSE if the error is set */ dbus_bool_t _dbus_read_uuid_file (const DBusString *filename, DBusGUID *uuid, dbus_bool_t create_if_not_found, DBusError *error) { DBusError read_error = DBUS_ERROR_INIT; if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error)) return TRUE; if (!create_if_not_found) { dbus_move_error (&read_error, error); return FALSE; } /* If the file exists and contains junk, we want to keep that error * message instead of overwriting it with a "file exists" error * message when we try to write */ if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT)) { dbus_move_error (&read_error, error); return FALSE; } else { dbus_error_free (&read_error); if (!_dbus_generate_uuid (uuid, error)) return FALSE; return _dbus_write_uuid_file (filename, uuid, error); } } /* Protected by _DBUS_LOCK (machine_uuid) */ static int machine_uuid_initialized_generation = 0; static DBusGUID machine_uuid; /** * Gets the hex-encoded UUID of the machine this function is * executed on. This UUID is guaranteed to be the same for a given * machine at least until it next reboots, though it also * makes some effort to be the same forever, it may change if the * machine is reconfigured or its hardware is modified. * * @param uuid_str string to append hex-encoded machine uuid to * @param error location to store reason for failure * @returns #TRUE if successful */ dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str, DBusError *error) { dbus_bool_t ok = TRUE; if (!_DBUS_LOCK (machine_uuid)) { _DBUS_SET_OOM (error); return FALSE; } if (machine_uuid_initialized_generation != _dbus_current_generation) { DBusError local_error = DBUS_ERROR_INIT; if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE, &local_error)) { #ifndef DBUS_ENABLE_EMBEDDED_TESTS /* For the test suite, we may not be installed so just continue silently * here. But in a production build, we want to be nice and loud about * this. */ _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n" "See the manual page for dbus-uuidgen to correct this issue.\n", local_error.message); #endif dbus_error_free (&local_error); ok = _dbus_generate_uuid (&machine_uuid, error); } } if (ok) { if (!_dbus_uuid_encode (&machine_uuid, uuid_str)) { ok = FALSE; _DBUS_SET_OOM (error); } } _DBUS_UNLOCK (machine_uuid); return ok; } #ifndef DBUS_DISABLE_CHECKS /** String used in _dbus_return_if_fail macro */ const char *_dbus_return_if_fail_warning_format = "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n" "This is normally a bug in some application using the D-Bus library.\n"; #endif #ifndef DBUS_DISABLE_ASSERT /** * Internals of _dbus_assert(); it's a function * rather than a macro with the inline code so * that the assertion failure blocks don't show up * in test suite coverage, and to shrink code size. * * @param condition TRUE if assertion succeeded * @param condition_text condition as a string * @param file file the assertion is in * @param line line the assertion is in * @param func function the assertion is in */ void _dbus_real_assert (dbus_bool_t condition, const char *condition_text, const char *file, int line, const char *func) { if (_DBUS_UNLIKELY (!condition)) { _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n", _dbus_pid_for_log (), condition_text, file, line, func); _dbus_abort (); } } /** * Internals of _dbus_assert_not_reached(); it's a function * rather than a macro with the inline code so * that the assertion failure blocks don't show up * in test suite coverage, and to shrink code size. * * @param explanation what was reached that shouldn't have been * @param file file the assertion is in * @param line line the assertion is in */ void _dbus_real_assert_not_reached (const char *explanation, const char *file, int line) { _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n", file, line, _dbus_pid_for_log (), explanation); _dbus_abort (); } #endif /* DBUS_DISABLE_ASSERT */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS static dbus_bool_t run_failing_each_malloc (int n_mallocs, const char *description, DBusTestMemoryFunction func, void *data) { n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */ while (n_mallocs >= 0) { _dbus_set_fail_alloc_counter (n_mallocs); _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n", description, n_mallocs, _dbus_get_fail_alloc_failures ()); if (!(* func) (data)) return FALSE; n_mallocs -= 1; } _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); return TRUE; } /** * Tests how well the given function responds to out-of-memory * situations. Calls the function repeatedly, failing a different * call to malloc() each time. If the function ever returns #FALSE, * the test fails. The function should return #TRUE whenever something * valid (such as returning an error, or succeeding) occurs, and #FALSE * if it gets confused in some way. * * @param description description of the test used in verbose output * @param func function to call * @param data data to pass to function * @returns #TRUE if the function never returns FALSE */ dbus_bool_t _dbus_test_oom_handling (const char *description, DBusTestMemoryFunction func, void *data) { int approx_mallocs; const char *setting; int max_failures_to_try; int i; /* Run once to see about how many mallocs are involved */ _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); _dbus_verbose ("Running once to count mallocs\n"); if (!(* func) (data)) return FALSE; approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter (); _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n", description, approx_mallocs); setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES"); if (setting != NULL) { DBusString str; long v; _dbus_string_init_const (&str, setting); v = 4; if (!_dbus_string_parse_int (&str, 0, &v, NULL)) _dbus_warn ("couldn't parse '%s' as integer\n", setting); max_failures_to_try = v; } else { max_failures_to_try = 4; } i = setting ? max_failures_to_try - 1 : 1; while (i < max_failures_to_try) { _dbus_set_fail_alloc_failures (i); if (!run_failing_each_malloc (approx_mallocs, description, func, data)) return FALSE; ++i; } _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n", description); return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** @} */ dbus-1.10.6/dbus/dbus-hash.h0000644000175000017500000001741012602773110015524 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-hash.h Generic hash table utility (internal to D-Bus implementation) * * Copyright (C) 2002 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_HASH_H #define DBUS_HASH_H #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusHashTable * @{ */ /** Hash iterator object. The iterator is on the stack, but its real * fields are hidden privately. */ struct DBusHashIter { void *dummy1; /**< Do not use. */ void *dummy2; /**< Do not use. */ void *dummy3; /**< Do not use. */ void *dummy4; /**< Do not use. */ int dummy5; /**< Do not use. */ int dummy6; /**< Do not use. */ }; typedef struct DBusHashTable DBusHashTable; typedef struct DBusHashIter DBusHashIter; /* Allowing an arbitrary function as with GLib * would be nicer for a public API, but for * an internal API this saves typing, we can add * more whenever we feel like it. */ typedef enum { DBUS_HASH_STRING, /**< Hash keys are strings. */ DBUS_HASH_INT, /**< Hash keys are integers. */ DBUS_HASH_UINTPTR /**< Hash keys are integer capable to hold a pointer. */ } DBusHashType; DBUS_PRIVATE_EXPORT DBusHashTable* _dbus_hash_table_new (DBusHashType type, DBusFreeFunction key_free_function, DBusFreeFunction value_free_function); DBusHashTable* _dbus_hash_table_ref (DBusHashTable *table); DBUS_PRIVATE_EXPORT void _dbus_hash_table_unref (DBusHashTable *table); void _dbus_hash_table_remove_all (DBusHashTable *table); DBUS_PRIVATE_EXPORT void _dbus_hash_iter_init (DBusHashTable *table, DBusHashIter *iter); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); DBUS_PRIVATE_EXPORT void _dbus_hash_iter_remove_entry (DBusHashIter *iter); DBUS_PRIVATE_EXPORT void* _dbus_hash_iter_get_value (DBusHashIter *iter); void _dbus_hash_iter_set_value (DBusHashIter *iter, void *value); DBUS_PRIVATE_EXPORT int _dbus_hash_iter_get_int_key (DBusHashIter *iter); DBUS_PRIVATE_EXPORT const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); DBUS_PRIVATE_EXPORT uintptr_t _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter); dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashIter *iter); DBUS_PRIVATE_EXPORT void* _dbus_hash_table_lookup_string (DBusHashTable *table, const char *key); DBUS_PRIVATE_EXPORT void* _dbus_hash_table_lookup_int (DBusHashTable *table, int key); DBUS_PRIVATE_EXPORT void* _dbus_hash_table_lookup_uintptr (DBusHashTable *table, uintptr_t key); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, const char *key); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, int key); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_remove_uintptr (DBusHashTable *table, uintptr_t key); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, char *key, void *value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, int key, void *value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_hash_table_insert_uintptr (DBusHashTable *table, uintptr_t key, void *value); DBUS_PRIVATE_EXPORT int _dbus_hash_table_get_n_entries (DBusHashTable *table); /* Preallocation */ /** A preallocated hash entry */ typedef struct DBusPreallocatedHash DBusPreallocatedHash; DBUS_PRIVATE_EXPORT DBusPreallocatedHash *_dbus_hash_table_preallocate_entry (DBusHashTable *table); DBUS_PRIVATE_EXPORT void _dbus_hash_table_free_preallocated_entry (DBusHashTable *table, DBusPreallocatedHash *preallocated); DBUS_PRIVATE_EXPORT void _dbus_hash_table_insert_string_preallocated (DBusHashTable *table, DBusPreallocatedHash *preallocated, char *key, void *value); #ifdef DBUS_WIN # define DBUS_HASH_POLLABLE DBUS_HASH_UINTPTR #else # define DBUS_HASH_POLLABLE DBUS_HASH_INT #endif static inline DBusPollable _dbus_hash_iter_get_pollable_key (DBusHashIter *iter) { #ifdef DBUS_WIN DBusSocket s; s.sock = _dbus_hash_iter_get_uintptr_key (iter); return s; #else return _dbus_hash_iter_get_int_key (iter); #endif } static inline void * _dbus_hash_table_lookup_pollable (DBusHashTable *table, DBusPollable key) { #ifdef DBUS_WIN return _dbus_hash_table_lookup_uintptr (table, key.sock); #else return _dbus_hash_table_lookup_int (table, key); #endif } static inline dbus_bool_t _dbus_hash_table_remove_pollable (DBusHashTable *table, DBusPollable key) { #ifdef DBUS_WIN return _dbus_hash_table_remove_uintptr (table, key.sock); #else return _dbus_hash_table_remove_int (table, key); #endif } static inline dbus_bool_t _dbus_hash_table_insert_pollable (DBusHashTable *table, DBusPollable key, void *value) { #ifdef DBUS_WIN return _dbus_hash_table_insert_uintptr (table, key.sock, value); #else return _dbus_hash_table_insert_int (table, key, value); #endif } /** @} */ DBUS_END_DECLS #endif /* DBUS_HASH_H */ dbus-1.10.6/dbus/dbus-hash.c0000644000175000017500000014514212602773110015523 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-hash.c Generic hash table utility (internal to D-Bus implementation) * * Copyright (C) 2002 Red Hat, Inc. * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * Hash table implementation based on generic/tclHash.c from the Tcl * source code. The original Tcl license applies to portions of the * code from tclHash.c; the Tcl license follows this standad D-Bus * license information. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /* * The following copyright applies to code from the Tcl distribution. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * This software is copyrighted by the Regents of the University of * California, Sun Microsystems, Inc., Scriptics Corporation, and * other parties. The following terms apply to all files associated * with the software unless explicitly disclaimed in individual files. * * The authors hereby grant permission to use, copy, modify, * distribute, and license this software and its documentation for any * purpose, provided that existing copyright notices are retained in * all copies and that this notice is included verbatim in any * distributions. No written agreement, license, or royalty fee is * required for any of the authorized uses. Modifications to this * software may be copyrighted by their authors and need not follow * the licensing terms described here, provided that the new terms are * clearly indicated on the first page of each file where they apply. * * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * GOVERNMENT USE: If you are acquiring this software on behalf of the * U.S. government, the Government shall have only "Restricted Rights" * in the software and related documentation as defined in the Federal * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you * are acquiring the software on behalf of the Department of Defense, * the software shall be classified as "Commercial Computer Software" * and the Government shall have only "Restricted Rights" as defined * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the * foregoing, the authors grant the U.S. Government and others acting * in its behalf permission to use and distribute the software in * accordance with the terms specified in this license. */ #include #include "dbus-hash.h" #include "dbus-internals.h" #include "dbus-mempool.h" /** * @defgroup DBusHashTable Hash table * @ingroup DBusInternals * @brief DBusHashTable data structure * * Types and functions related to DBusHashTable. */ /** * @defgroup DBusHashTableInternals Hash table implementation details * @ingroup DBusInternals * @brief DBusHashTable implementation details * * The guts of DBusHashTable. * * @{ */ /** * When there are this many entries per bucket, on average, rebuild * the hash table to make it larger. */ #define REBUILD_MULTIPLIER 3 /** * Takes a preliminary integer hash value and produces an index into a * hash tables bucket list. The idea is to make it so that * preliminary values that are arbitrarily similar will end up in * different buckets. The hash function was taken from a * random-number generator. (This is used to hash integers.) * * The down_shift drops off the high bits of the hash index, and * decreases as we increase the number of hash buckets (to keep more * range in the hash index). The mask also strips high bits and strips * fewer high bits as the number of hash buckets increases. * I don't understand two things: why is the initial downshift 28 * to keep 4 bits when the initial mask is 011 to keep 2 bits, * and why do we have both a mask and a downshift? * */ #define RANDOM_INDEX(table, i) \ (((((intptr_t) (i))*1103515245) >> (table)->down_shift) & (table)->mask) /** * Initial number of buckets in hash table (hash table statically * allocates its buckets for this size and below). * The initial mask has to be synced to this. */ #define DBUS_SMALL_HASH_TABLE 4 /** * Typedef for DBusHashEntry */ typedef struct DBusHashEntry DBusHashEntry; /** * @brief Internal representation of a hash entry. * * A single entry (key-value pair) in the hash table. * Internal to hash table implementation. */ struct DBusHashEntry { DBusHashEntry *next; /**< Pointer to next entry in this * hash bucket, or #NULL for end of * chain. */ void *key; /**< Hash key */ void *value; /**< Hash value */ }; /** * Function used to find and optionally create a hash entry. */ typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated); /** * @brief Internals of DBusHashTable. * * Hash table internals. Hash tables are opaque objects, they must be * used via accessor functions. */ struct DBusHashTable { int refcount; /**< Reference count */ DBusHashEntry **buckets; /**< Pointer to bucket array. Each * element points to first entry in * bucket's hash chain, or #NULL. */ DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE]; /**< Bucket array used for small tables * (to avoid mallocs and frees). */ int n_buckets; /**< Total number of buckets allocated * at **buckets. */ int n_entries; /**< Total number of entries present * in table. */ int hi_rebuild_size; /**< Enlarge table when n_entries gets * to be this large. */ int lo_rebuild_size; /**< Shrink table when n_entries gets * below this. */ int down_shift; /**< Shift count used in hashing * function. Designed to use high- * order bits of randomized keys. */ int mask; /**< Mask value used in hashing * function. */ DBusHashType key_type; /**< Type of keys used in this table */ DBusFindEntryFunction find_function; /**< Function for finding entries */ DBusFreeFunction free_key_function; /**< Function to free keys */ DBusFreeFunction free_value_function; /**< Function to free values */ DBusMemPool *entry_pool; /**< Memory pool for hash entries */ }; /** * @brief Internals of DBusHashIter. */ typedef struct { DBusHashTable *table; /**< Pointer to table containing entry. */ DBusHashEntry **bucket; /**< Pointer to bucket that points to * first entry in this entry's chain: * used for deleting the entry. */ DBusHashEntry *entry; /**< Current hash entry */ DBusHashEntry *next_entry; /**< Next entry to be iterated onto in current bucket */ int next_bucket; /**< index of next bucket */ int n_entries_on_init; /**< used to detect table resize since initialization */ } DBusRealHashIter; _DBUS_STATIC_ASSERT (sizeof (DBusRealHashIter) == sizeof (DBusHashIter)); static DBusHashEntry* find_direct_function (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated); static DBusHashEntry* find_string_function (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated); static unsigned int string_hash (const char *str); static void rebuild_table (DBusHashTable *table); static DBusHashEntry* alloc_entry (DBusHashTable *table); static void remove_entry (DBusHashTable *table, DBusHashEntry **bucket, DBusHashEntry *entry); static void free_entry (DBusHashTable *table, DBusHashEntry *entry); static void free_entry_data (DBusHashTable *table, DBusHashEntry *entry); /** @} */ /** * @addtogroup DBusHashTable * @{ */ /** * @typedef DBusHashIter * * Public opaque hash table iterator object. */ /** * @typedef DBusHashTable * * Public opaque hash table object. */ /** * @typedef DBusHashType * * Indicates the type of a key in the hash table. */ /** * Constructs a new hash table. Should be freed with * _dbus_hash_table_unref(). If memory cannot be * allocated for the hash table, returns #NULL. * * @param type the type of hash key to use. * @param key_free_function function to free hash keys. * @param value_free_function function to free hash values. * @returns a new DBusHashTable or #NULL if no memory. */ DBusHashTable* _dbus_hash_table_new (DBusHashType type, DBusFreeFunction key_free_function, DBusFreeFunction value_free_function) { DBusHashTable *table; DBusMemPool *entry_pool; table = dbus_new0 (DBusHashTable, 1); if (table == NULL) return NULL; entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE); if (entry_pool == NULL) { dbus_free (table); return NULL; } table->refcount = 1; table->entry_pool = entry_pool; _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets)); table->buckets = table->static_buckets; table->n_buckets = DBUS_SMALL_HASH_TABLE; table->n_entries = 0; table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER; table->lo_rebuild_size = 0; table->down_shift = 28; table->mask = 3; table->key_type = type; _dbus_assert (table->mask < table->n_buckets); switch (table->key_type) { case DBUS_HASH_INT: case DBUS_HASH_UINTPTR: table->find_function = find_direct_function; break; case DBUS_HASH_STRING: table->find_function = find_string_function; break; default: _dbus_assert_not_reached ("Unknown hash table type"); break; } table->free_key_function = key_free_function; table->free_value_function = value_free_function; return table; } /** * Increments the reference count for a hash table. * * @param table the hash table to add a reference to. * @returns the hash table. */ DBusHashTable * _dbus_hash_table_ref (DBusHashTable *table) { table->refcount += 1; return table; } /** * Decrements the reference count for a hash table, * freeing the hash table if the count reaches zero. * * @param table the hash table to remove a reference from. */ void _dbus_hash_table_unref (DBusHashTable *table) { table->refcount -= 1; if (table->refcount == 0) { #if 0 DBusHashEntry *entry; DBusHashEntry *next; int i; /* Free the entries in the table. */ for (i = 0; i < table->n_buckets; i++) { entry = table->buckets[i]; while (entry != NULL) { next = entry->next; free_entry (table, entry); entry = next; } } #else DBusHashEntry *entry; int i; /* Free the entries in the table. */ for (i = 0; i < table->n_buckets; i++) { entry = table->buckets[i]; while (entry != NULL) { free_entry_data (table, entry); entry = entry->next; } } /* We can do this very quickly with memory pools ;-) */ _dbus_mem_pool_free (table->entry_pool); #endif /* Free the bucket array, if it was dynamically allocated. */ if (table->buckets != table->static_buckets) dbus_free (table->buckets); dbus_free (table); } } /** * Removed all entries from a hash table. * * @param table the hash table to remove all entries from. */ void _dbus_hash_table_remove_all (DBusHashTable *table) { DBusHashIter iter; _dbus_hash_iter_init (table, &iter); while (_dbus_hash_iter_next (&iter)) { _dbus_hash_iter_remove_entry(&iter); } } static DBusHashEntry* alloc_entry (DBusHashTable *table) { DBusHashEntry *entry; entry = _dbus_mem_pool_alloc (table->entry_pool); return entry; } static void free_entry_data (DBusHashTable *table, DBusHashEntry *entry) { if (table->free_key_function) (* table->free_key_function) (entry->key); if (table->free_value_function) (* table->free_value_function) (entry->value); } static void free_entry (DBusHashTable *table, DBusHashEntry *entry) { free_entry_data (table, entry); _dbus_mem_pool_dealloc (table->entry_pool, entry); } static void remove_entry (DBusHashTable *table, DBusHashEntry **bucket, DBusHashEntry *entry) { _dbus_assert (table != NULL); _dbus_assert (bucket != NULL); _dbus_assert (*bucket != NULL); _dbus_assert (entry != NULL); if (*bucket == entry) *bucket = entry->next; else { DBusHashEntry *prev; prev = *bucket; while (prev->next != entry) prev = prev->next; _dbus_assert (prev != NULL); prev->next = entry->next; } table->n_entries -= 1; free_entry (table, entry); } /** * Initializes a hash table iterator. To iterate over all entries in a * hash table, use the following code (the printf assumes a hash * from strings to strings obviously): * * @code * DBusHashIter iter; * * _dbus_hash_iter_init (table, &iter); * while (_dbus_hash_iter_next (&iter)) * { * printf ("The first key is %s and value is %s\n", * _dbus_hash_iter_get_string_key (&iter), * _dbus_hash_iter_get_value (&iter)); * } * * * @endcode * * The iterator is initialized pointing "one before" the first hash * entry. The first call to _dbus_hash_iter_next() moves it onto * the first valid entry or returns #FALSE if the hash table is * empty. Subsequent calls move to the next valid entry or return * #FALSE if there are no more entries. * * Note that it is guaranteed to be safe to remove a hash entry during * iteration, but it is not safe to add a hash entry. * * @param table the hash table to iterate over. * @param iter the iterator to initialize. */ void _dbus_hash_iter_init (DBusHashTable *table, DBusHashIter *iter) { DBusRealHashIter *real; _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); real = (DBusRealHashIter*) iter; real->table = table; real->bucket = NULL; real->entry = NULL; real->next_entry = NULL; real->next_bucket = 0; real->n_entries_on_init = table->n_entries; } /** * Move the hash iterator forward one step, to the next hash entry. * The documentation for _dbus_hash_iter_init() explains in more * detail. * * @param iter the iterator to move forward. * @returns #FALSE if there are no more entries to move to. */ dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter) { DBusRealHashIter *real; _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); real = (DBusRealHashIter*) iter; /* if this assertion failed someone probably added hash entries * during iteration, which is bad. */ _dbus_assert (real->n_entries_on_init >= real->table->n_entries); /* Remember that real->entry may have been deleted */ while (real->next_entry == NULL) { if (real->next_bucket >= real->table->n_buckets) { /* invalidate iter and return false */ real->entry = NULL; real->table = NULL; real->bucket = NULL; return FALSE; } real->bucket = &(real->table->buckets[real->next_bucket]); real->next_entry = *(real->bucket); real->next_bucket += 1; } _dbus_assert (real->next_entry != NULL); _dbus_assert (real->bucket != NULL); real->entry = real->next_entry; real->next_entry = real->entry->next; return TRUE; } /** * Removes the current entry from the hash table. * If a key_free_function or value_free_function * was provided to _dbus_hash_table_new(), * frees the key and/or value for this entry. * * @param iter the hash table iterator. */ void _dbus_hash_iter_remove_entry (DBusHashIter *iter) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); _dbus_assert (real->bucket != NULL); remove_entry (real->table, real->bucket, real->entry); real->entry = NULL; /* make it crash if you try to use this entry */ } /** * Gets the value of the current entry. * * @param iter the hash table iterator. */ void* _dbus_hash_iter_get_value (DBusHashIter *iter) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); return real->entry->value; } /** * Sets the value of the current entry. * If the hash table has a value_free_function * it will be used to free the previous value. * The hash table will own the passed-in value * (it will not be copied). * * @param iter the hash table iterator. * @param value the new value. */ void _dbus_hash_iter_set_value (DBusHashIter *iter, void *value) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); if (real->table->free_value_function && value != real->entry->value) (* real->table->free_value_function) (real->entry->value); real->entry->value = value; } /** * Gets the key for the current entry. * Only works for hash tables of type #DBUS_HASH_INT. * * @param iter the hash table iterator. */ int _dbus_hash_iter_get_int_key (DBusHashIter *iter) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); return _DBUS_POINTER_TO_INT (real->entry->key); } /** * Gets the key for the current entry. * Only works for hash tables of type #DBUS_HASH_UINTPTR. * * @param iter the hash table iterator. */ uintptr_t _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); return (uintptr_t) real->entry->key; } /** * Gets the key for the current entry. * Only works for hash tables of type #DBUS_HASH_STRING * @param iter the hash table iterator. */ const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter) { DBusRealHashIter *real; real = (DBusRealHashIter*) iter; _dbus_assert (real->table != NULL); _dbus_assert (real->entry != NULL); return real->entry->key; } /** * A low-level but efficient interface for manipulating the hash * table. It's efficient because you can get, set, and optionally * create the hash entry while only running the hash function one * time. * * Note that while calling _dbus_hash_iter_next() on the iterator * filled in by this function may work, it's completely * undefined which entries are after this iter and which * are before it. So it would be silly to iterate using this * iterator. * * If the hash entry is created, its value will be initialized * to all bits zero. * * #FALSE may be returned due to memory allocation failure, or * because create_if_not_found was #FALSE and the entry * did not exist. * * If create_if_not_found is #TRUE and the entry is created, the hash * table takes ownership of the key that's passed in. * * For a hash table of type #DBUS_HASH_INT, cast the int * key to the key parameter using #_DBUS_INT_TO_POINTER(). * * @param table the hash table. * @param key the hash key. * @param create_if_not_found if #TRUE, create the entry if it didn't exist. * @param iter the iterator to initialize. * @returns #TRUE if the hash entry now exists (and the iterator is thus valid). */ dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashIter *iter) { DBusRealHashIter *real; DBusHashEntry *entry; DBusHashEntry **bucket; _DBUS_STATIC_ASSERT (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); real = (DBusRealHashIter*) iter; entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL); if (entry == NULL) return FALSE; real->table = table; real->bucket = bucket; real->entry = entry; real->next_entry = entry->next; real->next_bucket = (bucket - table->buckets) + 1; real->n_entries_on_init = table->n_entries; _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket); return TRUE; } static void add_allocated_entry (DBusHashTable *table, DBusHashEntry *entry, unsigned int idx, void *key, DBusHashEntry ***bucket) { DBusHashEntry **b; entry->key = key; b = &(table->buckets[idx]); entry->next = *b; *b = entry; if (bucket) *bucket = b; table->n_entries += 1; /* note we ONLY rebuild when ADDING - because you can iterate over a * table and remove entries safely. */ if (table->n_entries >= table->hi_rebuild_size || table->n_entries < table->lo_rebuild_size) rebuild_table (table); } static DBusHashEntry* add_entry (DBusHashTable *table, unsigned int idx, void *key, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated) { DBusHashEntry *entry; if (preallocated == NULL) { entry = alloc_entry (table); if (entry == NULL) { if (bucket) *bucket = NULL; return NULL; } } else { entry = (DBusHashEntry*) preallocated; } add_allocated_entry (table, entry, idx, key, bucket); return entry; } /* This is g_str_hash from GLib which was * extensively discussed/tested/profiled */ static unsigned int string_hash (const char *str) { const char *p = str; unsigned int h = *p; if (h) for (p += 1; *p != '\0'; p++) h = (h << 5) - h + *p; return h; } /** Key comparison function */ typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); static DBusHashEntry* find_generic_function (DBusHashTable *table, void *key, unsigned int idx, KeyCompareFunc compare_func, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated) { DBusHashEntry *entry; if (bucket) *bucket = NULL; /* Search all of the entries in this bucket. */ entry = table->buckets[idx]; while (entry != NULL) { if ((compare_func == NULL && key == entry->key) || (compare_func != NULL && (* compare_func) (key, entry->key) == 0)) { if (bucket) *bucket = &(table->buckets[idx]); if (preallocated) _dbus_hash_table_free_preallocated_entry (table, preallocated); return entry; } entry = entry->next; } if (create_if_not_found) entry = add_entry (table, idx, key, bucket, preallocated); else if (preallocated) _dbus_hash_table_free_preallocated_entry (table, preallocated); return entry; } static DBusHashEntry* find_string_function (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated) { unsigned int idx; idx = string_hash (key) & table->mask; return find_generic_function (table, key, idx, (KeyCompareFunc) strcmp, create_if_not_found, bucket, preallocated); } static DBusHashEntry* find_direct_function (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated) { unsigned int idx; idx = RANDOM_INDEX (table, key) & table->mask; return find_generic_function (table, key, idx, NULL, create_if_not_found, bucket, preallocated); } static void rebuild_table (DBusHashTable *table) { int old_size; int new_buckets; DBusHashEntry **old_buckets; DBusHashEntry **old_chain; DBusHashEntry *entry; dbus_bool_t growing; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ growing = table->n_entries >= table->hi_rebuild_size; old_size = table->n_buckets; old_buckets = table->buckets; if (growing) { /* overflow paranoia */ if (table->n_buckets < _DBUS_INT_MAX / 4 && table->down_shift >= 0) new_buckets = table->n_buckets * 4; else return; /* can't grow anymore */ } else { new_buckets = table->n_buckets / 4; if (new_buckets < DBUS_SMALL_HASH_TABLE) return; /* don't bother shrinking this far */ } table->buckets = dbus_new0 (DBusHashEntry*, new_buckets); if (table->buckets == NULL) { /* out of memory, yay - just don't reallocate, the table will * still work, albeit more slowly. */ table->buckets = old_buckets; return; } table->n_buckets = new_buckets; if (growing) { table->lo_rebuild_size = table->hi_rebuild_size; table->hi_rebuild_size *= 4; table->down_shift -= 2; /* keep 2 more high bits */ table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */ } else { table->hi_rebuild_size = table->lo_rebuild_size; table->lo_rebuild_size /= 4; table->down_shift += 2; /* keep 2 fewer high bits */ table->mask = table->mask >> 2; /* keep 2 fewer high bits */ } #if 0 printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n", growing ? "GROW" : "SHRINK", table->lo_rebuild_size, table->hi_rebuild_size, table->down_shift, table->mask); #endif _dbus_assert (table->lo_rebuild_size >= 0); _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size); _dbus_assert (table->mask != 0); /* the mask is essentially the max index */ _dbus_assert (table->mask < table->n_buckets); /* * Rehash all of the existing entries into the new bucket array. */ for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++) { for (entry = *old_chain; entry != NULL; entry = *old_chain) { unsigned int idx; DBusHashEntry **bucket; *old_chain = entry->next; switch (table->key_type) { case DBUS_HASH_STRING: idx = string_hash (entry->key) & table->mask; break; case DBUS_HASH_INT: case DBUS_HASH_UINTPTR: idx = RANDOM_INDEX (table, entry->key); break; default: idx = 0; _dbus_assert_not_reached ("Unknown hash table type"); break; } bucket = &(table->buckets[idx]); entry->next = *bucket; *bucket = entry; } } /* Free the old bucket array, if it was dynamically allocated. */ if (old_buckets != table->static_buckets) dbus_free (old_buckets); } /** * Looks up the value for a given string in a hash table * of type #DBUS_HASH_STRING. Returns %NULL if the value * is not present. (A not-present entry is indistinguishable * from an entry with a value of %NULL.) * @param table the hash table. * @param key the string to look up. * @returns the value of the hash entry. */ void* _dbus_hash_table_lookup_string (DBusHashTable *table, const char *key) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_STRING); entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL); if (entry) return entry->value; else return NULL; } /** * Looks up the value for a given integer in a hash table * of type #DBUS_HASH_INT. Returns %NULL if the value * is not present. (A not-present entry is indistinguishable * from an entry with a value of %NULL.) * @param table the hash table. * @param key the integer to look up. * @returns the value of the hash entry. */ void* _dbus_hash_table_lookup_int (DBusHashTable *table, int key) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_INT); entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL); if (entry) return entry->value; else return NULL; } /** * Looks up the value for a given integer in a hash table * of type #DBUS_HASH_UINTPTR. Returns %NULL if the value * is not present. (A not-present entry is indistinguishable * from an entry with a value of %NULL.) * @param table the hash table. * @param key the integer to look up. * @returns the value of the hash entry. */ void* _dbus_hash_table_lookup_uintptr (DBusHashTable *table, uintptr_t key) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL); if (entry) return entry->value; else return NULL; } /** * Removes the hash entry for the given key. If no hash entry * for the key exists, does nothing. * * @param table the hash table. * @param key the hash key. * @returns #TRUE if the entry existed */ dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, const char *key) { DBusHashEntry *entry; DBusHashEntry **bucket; _dbus_assert (table->key_type == DBUS_HASH_STRING); entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL); if (entry) { remove_entry (table, bucket, entry); return TRUE; } else return FALSE; } /** * Removes the hash entry for the given key. If no hash entry * for the key exists, does nothing. * * @param table the hash table. * @param key the hash key. * @returns #TRUE if the entry existed */ dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, int key) { DBusHashEntry *entry; DBusHashEntry **bucket; _dbus_assert (table->key_type == DBUS_HASH_INT); entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL); if (entry) { remove_entry (table, bucket, entry); return TRUE; } else return FALSE; } /** * Removes the hash entry for the given key. If no hash entry * for the key exists, does nothing. * * @param table the hash table. * @param key the hash key. * @returns #TRUE if the entry existed */ dbus_bool_t _dbus_hash_table_remove_uintptr (DBusHashTable *table, uintptr_t key) { DBusHashEntry *entry; DBusHashEntry **bucket; _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL); if (entry) { remove_entry (table, bucket, entry); return TRUE; } else return FALSE; } /** * Creates a hash entry with the given key and value. * The key and value are not copied; they are stored * in the hash table by reference. If an entry with the * given key already exists, the previous key and value * are overwritten (and freed if the hash table has * a key_free_function and/or value_free_function). * * Returns #FALSE if memory for the new hash entry * can't be allocated. * * @param table the hash table. * @param key the hash entry key. * @param value the hash entry value. */ dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, char *key, void *value) { DBusPreallocatedHash *preallocated; _dbus_assert (table->key_type == DBUS_HASH_STRING); preallocated = _dbus_hash_table_preallocate_entry (table); if (preallocated == NULL) return FALSE; _dbus_hash_table_insert_string_preallocated (table, preallocated, key, value); return TRUE; } /** * Creates a hash entry with the given key and value. * The key and value are not copied; they are stored * in the hash table by reference. If an entry with the * given key already exists, the previous key and value * are overwritten (and freed if the hash table has * a key_free_function and/or value_free_function). * * Returns #FALSE if memory for the new hash entry * can't be allocated. * * @param table the hash table. * @param key the hash entry key. * @param value the hash entry value. */ dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, int key, void *value) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_INT); entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL); if (entry == NULL) return FALSE; /* no memory */ if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key)) (* table->free_key_function) (entry->key); if (table->free_value_function && entry->value != value) (* table->free_value_function) (entry->value); entry->key = _DBUS_INT_TO_POINTER (key); entry->value = value; return TRUE; } /** * Creates a hash entry with the given key and value. * The key and value are not copied; they are stored * in the hash table by reference. If an entry with the * given key already exists, the previous key and value * are overwritten (and freed if the hash table has * a key_free_function and/or value_free_function). * * Returns #FALSE if memory for the new hash entry * can't be allocated. * * @param table the hash table. * @param key the hash entry key. * @param value the hash entry value. */ dbus_bool_t _dbus_hash_table_insert_uintptr (DBusHashTable *table, uintptr_t key, void *value) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_UINTPTR); entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL); if (entry == NULL) return FALSE; /* no memory */ if (table->free_key_function && entry->key != (void*) key) (* table->free_key_function) (entry->key); if (table->free_value_function && entry->value != value) (* table->free_value_function) (entry->value); entry->key = (void*) key; entry->value = value; return TRUE; } /** * Preallocate an opaque data blob that allows us to insert into the * hash table at a later time without allocating any memory. * * @param table the hash table * @returns the preallocated data, or #NULL if no memory */ DBusPreallocatedHash* _dbus_hash_table_preallocate_entry (DBusHashTable *table) { DBusHashEntry *entry; entry = alloc_entry (table); return (DBusPreallocatedHash*) entry; } /** * Frees an opaque DBusPreallocatedHash that was *not* used * in order to insert into the hash table. * * @param table the hash table * @param preallocated the preallocated data */ void _dbus_hash_table_free_preallocated_entry (DBusHashTable *table, DBusPreallocatedHash *preallocated) { DBusHashEntry *entry; _dbus_assert (preallocated != NULL); entry = (DBusHashEntry*) preallocated; /* Don't use free_entry(), since this entry has no key/data */ _dbus_mem_pool_dealloc (table->entry_pool, entry); } /** * Inserts a string-keyed entry into the hash table, using a * preallocated data block from * _dbus_hash_table_preallocate_entry(). This function cannot fail due * to lack of memory. The DBusPreallocatedHash object is consumed and * should not be reused or freed. Otherwise this function works * just like _dbus_hash_table_insert_string(). * * @param table the hash table * @param preallocated the preallocated data * @param key the hash key * @param value the value */ void _dbus_hash_table_insert_string_preallocated (DBusHashTable *table, DBusPreallocatedHash *preallocated, char *key, void *value) { DBusHashEntry *entry; _dbus_assert (table->key_type == DBUS_HASH_STRING); _dbus_assert (preallocated != NULL); entry = (* table->find_function) (table, key, TRUE, NULL, preallocated); _dbus_assert (entry != NULL); if (table->free_key_function && entry->key != key) (* table->free_key_function) (entry->key); if (table->free_value_function && entry->value != value) (* table->free_value_function) (entry->value); entry->key = key; entry->value = value; } /** * Gets the number of hash entries in a hash table. * * @param table the hash table. * @returns the number of entries in the table. */ int _dbus_hash_table_get_n_entries (DBusHashTable *table) { return table->n_entries; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include /* If you're wondering why the hash table test takes * forever to run, it's because we call this function * in inner loops thus making things quadratic. */ static int count_entries (DBusHashTable *table) { DBusHashIter iter; int count; count = 0; _dbus_hash_iter_init (table, &iter); while (_dbus_hash_iter_next (&iter)) ++count; _dbus_assert (count == _dbus_hash_table_get_n_entries (table)); return count; } /** * @ingroup DBusHashTableInternals * Unit test for DBusHashTable * @returns #TRUE on success. */ dbus_bool_t _dbus_hash_test (void) { int i; DBusHashTable *table1; DBusHashTable *table2; DBusHashTable *table3; DBusHashIter iter; #define N_HASH_KEYS 5000 char **keys; dbus_bool_t ret = FALSE; keys = dbus_new (char *, N_HASH_KEYS); if (keys == NULL) _dbus_assert_not_reached ("no memory"); for (i = 0; i < N_HASH_KEYS; i++) { keys[i] = dbus_malloc (128); if (keys[i] == NULL) _dbus_assert_not_reached ("no memory"); } printf ("Computing test hash keys...\n"); i = 0; while (i < N_HASH_KEYS) { int len; len = sprintf (keys[i], "Hash key %d", i); _dbus_assert (*(keys[i] + len) == '\0'); ++i; } printf ("... done.\n"); table1 = _dbus_hash_table_new (DBUS_HASH_STRING, dbus_free, dbus_free); if (table1 == NULL) goto out; table2 = _dbus_hash_table_new (DBUS_HASH_INT, NULL, dbus_free); if (table2 == NULL) goto out; table3 = _dbus_hash_table_new (DBUS_HASH_UINTPTR, NULL, dbus_free); if (table3 == NULL) goto out; /* Insert and remove a bunch of stuff, counting the table in between * to be sure it's not broken and that iteration works */ i = 0; while (i < 3000) { void *value; char *key; key = _dbus_strdup (keys[i]); if (key == NULL) goto out; value = _dbus_strdup ("Value!"); if (value == NULL) goto out; if (!_dbus_hash_table_insert_string (table1, key, value)) goto out; value = _dbus_strdup (keys[i]); if (value == NULL) goto out; if (!_dbus_hash_table_insert_int (table2, i, value)) goto out; value = _dbus_strdup (keys[i]); if (value == NULL) goto out; if (!_dbus_hash_table_insert_uintptr (table3, i, value)) goto out; _dbus_assert (count_entries (table1) == i + 1); _dbus_assert (count_entries (table2) == i + 1); _dbus_assert (count_entries (table3) == i + 1); value = _dbus_hash_table_lookup_string (table1, keys[i]); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, "Value!") == 0); value = _dbus_hash_table_lookup_int (table2, i); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); value = _dbus_hash_table_lookup_uintptr (table3, i); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); ++i; } --i; while (i >= 0) { _dbus_hash_table_remove_string (table1, keys[i]); _dbus_hash_table_remove_int (table2, i); _dbus_hash_table_remove_uintptr (table3, i); _dbus_assert (count_entries (table1) == i); _dbus_assert (count_entries (table2) == i); _dbus_assert (count_entries (table3) == i); --i; } _dbus_hash_table_ref (table1); _dbus_hash_table_ref (table2); _dbus_hash_table_ref (table3); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); _dbus_hash_table_unref (table3); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); _dbus_hash_table_unref (table3); table3 = NULL; /* Insert a bunch of stuff then check * that iteration works correctly (finds the right * values, iter_set_value works, etc.) */ table1 = _dbus_hash_table_new (DBUS_HASH_STRING, dbus_free, dbus_free); if (table1 == NULL) goto out; table2 = _dbus_hash_table_new (DBUS_HASH_INT, NULL, dbus_free); if (table2 == NULL) goto out; i = 0; while (i < 5000) { char *key; void *value; key = _dbus_strdup (keys[i]); if (key == NULL) goto out; value = _dbus_strdup ("Value!"); if (value == NULL) goto out; if (!_dbus_hash_table_insert_string (table1, key, value)) goto out; value = _dbus_strdup (keys[i]); if (value == NULL) goto out; if (!_dbus_hash_table_insert_int (table2, i, value)) goto out; _dbus_assert (count_entries (table1) == i + 1); _dbus_assert (count_entries (table2) == i + 1); ++i; } _dbus_hash_iter_init (table1, &iter); while (_dbus_hash_iter_next (&iter)) { const char *key; void *value; key = _dbus_hash_iter_get_string_key (&iter); value = _dbus_hash_iter_get_value (&iter); _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); value = _dbus_strdup ("Different value!"); if (value == NULL) goto out; _dbus_hash_iter_set_value (&iter, value); _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); } _dbus_hash_iter_init (table1, &iter); while (_dbus_hash_iter_next (&iter)) { _dbus_hash_iter_remove_entry (&iter); _dbus_assert (count_entries (table1) == i - 1); --i; } _dbus_hash_iter_init (table2, &iter); while (_dbus_hash_iter_next (&iter)) { int key; void *value; key = _dbus_hash_iter_get_int_key (&iter); value = _dbus_hash_iter_get_value (&iter); _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); value = _dbus_strdup ("Different value!"); if (value == NULL) goto out; _dbus_hash_iter_set_value (&iter, value); _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); } i = count_entries (table2); _dbus_hash_iter_init (table2, &iter); while (_dbus_hash_iter_next (&iter)) { _dbus_hash_iter_remove_entry (&iter); _dbus_assert (count_entries (table2) + 1 == i); --i; } /* add/remove interleaved, to check that we grow/shrink the table * appropriately */ i = 0; while (i < 1000) { char *key; void *value; key = _dbus_strdup (keys[i]); if (key == NULL) goto out; value = _dbus_strdup ("Value!"); if (value == NULL) goto out; if (!_dbus_hash_table_insert_string (table1, key, value)) goto out; ++i; } --i; while (i >= 0) { char *key; void *value; key = _dbus_strdup (keys[i]); if (key == NULL) goto out; value = _dbus_strdup ("Value!"); if (value == NULL) goto out; if (!_dbus_hash_table_remove_string (table1, keys[i])) goto out; if (!_dbus_hash_table_insert_string (table1, key, value)) goto out; if (!_dbus_hash_table_remove_string (table1, keys[i])) goto out; _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i); --i; } /* nuke these tables */ _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); /* Now do a bunch of things again using _dbus_hash_iter_lookup() to * be sure that interface works. */ table1 = _dbus_hash_table_new (DBUS_HASH_STRING, dbus_free, dbus_free); if (table1 == NULL) goto out; table2 = _dbus_hash_table_new (DBUS_HASH_INT, NULL, dbus_free); if (table2 == NULL) goto out; i = 0; while (i < 3000) { void *value; char *key; key = _dbus_strdup (keys[i]); if (key == NULL) goto out; value = _dbus_strdup ("Value!"); if (value == NULL) goto out; if (!_dbus_hash_iter_lookup (table1, key, TRUE, &iter)) goto out; _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); _dbus_hash_iter_set_value (&iter, value); value = _dbus_strdup (keys[i]); if (value == NULL) goto out; if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), TRUE, &iter)) goto out; _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); _dbus_hash_iter_set_value (&iter, value); _dbus_assert (count_entries (table1) == i + 1); _dbus_assert (count_entries (table2) == i + 1); if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) goto out; value = _dbus_hash_iter_get_value (&iter); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, "Value!") == 0); /* Iterate just to be sure it works, though * it's a stupid thing to do */ while (_dbus_hash_iter_next (&iter)) ; if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) goto out; value = _dbus_hash_iter_get_value (&iter); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); /* Iterate just to be sure it works, though * it's a stupid thing to do */ while (_dbus_hash_iter_next (&iter)) ; ++i; } --i; while (i >= 0) { if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) _dbus_assert_not_reached ("hash entry should have existed"); _dbus_hash_iter_remove_entry (&iter); if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) _dbus_assert_not_reached ("hash entry should have existed"); _dbus_hash_iter_remove_entry (&iter); _dbus_assert (count_entries (table1) == i); _dbus_assert (count_entries (table2) == i); --i; } _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); ret = TRUE; out: for (i = 0; i < N_HASH_KEYS; i++) dbus_free (keys[i]); dbus_free (keys); return ret; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-file.h0000644000175000017500000000440612602773110015521 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-file.h dbus file related stuff (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_FILE_H #define DBUS_FILE_H //#include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusFile * @{ */ /** * File interface */ dbus_bool_t _dbus_file_exists (const char *file); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_file_get_contents (DBusString *str, const DBusString *filename, DBusError *error); dbus_bool_t _dbus_string_save_to_file (const DBusString *str, const DBusString *filename, dbus_bool_t world_readable, DBusError *error); dbus_bool_t _dbus_make_file_world_readable (const DBusString *filename, DBusError *error); dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_delete_file (const DBusString *filename, DBusError *error); /** @} */ DBUS_END_DECLS #endif dbus-1.10.6/dbus/dbus-file.c0000644000175000017500000000210412602773110015505 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation) * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-file.h" dbus-1.10.6/dbus/dbus-dataslot.h0000644000175000017500000000741112602773110016414 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-dataslot.h storing data on objects * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_DATASLOT_H #define DBUS_DATASLOT_H #include DBUS_BEGIN_DECLS typedef struct DBusDataSlotAllocator DBusDataSlotAllocator; typedef struct DBusDataSlotList DBusDataSlotList; /** Opaque typedef for DBusDataSlot */ typedef struct DBusDataSlot DBusDataSlot; /** DBusDataSlot is used to store application data on the connection */ struct DBusDataSlot { void *data; /**< The application data */ DBusFreeFunction free_data_func; /**< Free the application data */ }; typedef struct DBusAllocatedSlot DBusAllocatedSlot; /** An allocated slot for storing data */ struct DBusAllocatedSlot { dbus_int32_t slot_id; /**< ID of this slot */ int refcount; /**< Number of uses of the slot */ }; /** * An allocator that tracks a set of slot IDs. */ struct DBusDataSlotAllocator { DBusAllocatedSlot *allocated_slots; /**< Allocated slots */ int n_allocated_slots; /**< number of slots malloc'd */ int n_used_slots; /**< number of slots used */ DBusGlobalLock lock; /**< index of thread lock */ }; #define _DBUS_DATA_SLOT_ALLOCATOR_INIT(x) { NULL, 0, 0, x } /** * Data structure that stores the actual user data set at a given * slot. */ struct DBusDataSlotList { DBusDataSlot *slots; /**< Data slots */ int n_slots; /**< Slots we have storage for in data_slots */ }; dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator, DBusGlobalLock lock); dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, int *slot_id_p); void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, int *slot_id_p); void _dbus_data_slot_list_init (DBusDataSlotList *list); dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot, void *data, DBusFreeFunction free_data_func, DBusFreeFunction *old_free_func, void **old_data); void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot); void _dbus_data_slot_list_clear (DBusDataSlotList *list); void _dbus_data_slot_list_free (DBusDataSlotList *list); DBUS_END_DECLS #endif /* DBUS_DATASLOT_H */ dbus-1.10.6/dbus/dbus-dataslot.c0000644000175000017500000003201112602773110016401 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-dataslot.c storing data on objects * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-dataslot.h" #include "dbus-threads-internal.h" /** * @defgroup DBusDataSlot Data slots * @ingroup DBusInternals * @brief Storing data by ID * * Types and functions related to storing data by an * allocated ID. This is used for dbus_connection_set_data(), * dbus_server_set_data(), etc. * @{ */ /** * Initializes a data slot allocator object, used to assign * integer IDs for data slots. * * @param allocator the allocator to initialize */ dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator, DBusGlobalLock lock) { allocator->allocated_slots = NULL; allocator->n_allocated_slots = 0; allocator->n_used_slots = 0; allocator->lock = lock; return TRUE; } /** * Allocates an integer ID to be used for storing data * in a #DBusDataSlotList. If the value at *slot_id_p is * not -1, this function just increments the refcount for * the existing slot ID. If the value is -1, a new slot ID * is allocated and stored at *slot_id_p. * * @param allocator the allocator * @param slot_id_p address to fill with the slot ID * @returns #TRUE on success */ dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, dbus_int32_t *slot_id_p) { dbus_int32_t slot; if (!_dbus_lock (allocator->lock)) return FALSE; if (*slot_id_p >= 0) { slot = *slot_id_p; _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); allocator->allocated_slots[slot].refcount += 1; goto out; } _dbus_assert (*slot_id_p < 0); if (allocator->n_used_slots < allocator->n_allocated_slots) { slot = 0; while (slot < allocator->n_allocated_slots) { if (allocator->allocated_slots[slot].slot_id < 0) { allocator->allocated_slots[slot].slot_id = slot; allocator->allocated_slots[slot].refcount = 1; allocator->n_used_slots += 1; break; } ++slot; } _dbus_assert (slot < allocator->n_allocated_slots); } else { DBusAllocatedSlot *tmp; slot = -1; tmp = dbus_realloc (allocator->allocated_slots, sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1)); if (tmp == NULL) goto out; allocator->allocated_slots = tmp; slot = allocator->n_allocated_slots; allocator->n_allocated_slots += 1; allocator->n_used_slots += 1; allocator->allocated_slots[slot].slot_id = slot; allocator->allocated_slots[slot].refcount = 1; } _dbus_assert (slot >= 0); _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (*slot_id_p < 0); _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); _dbus_assert (allocator->allocated_slots[slot].refcount == 1); *slot_id_p = slot; _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n", slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots); out: _dbus_unlock (allocator->lock); return slot >= 0; } /** * Deallocates an ID previously allocated with * _dbus_data_slot_allocator_alloc(). Existing data stored on * existing #DBusDataSlotList objects with this ID will be freed when the * data list is finalized, but may not be retrieved (and may only be * replaced if someone else reallocates the slot). * The slot value is reset to -1 if this is the last unref. * * @param allocator the allocator * @param slot_id_p address where we store the slot */ void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, dbus_int32_t *slot_id_p) { if (!_dbus_lock (allocator->lock)) _dbus_assert_not_reached ("we should have initialized global locks " "before we allocated this slot"); _dbus_assert (*slot_id_p < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p); _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0); allocator->allocated_slots[*slot_id_p].refcount -= 1; if (allocator->allocated_slots[*slot_id_p].refcount > 0) { _dbus_unlock (allocator->lock); return; } /* refcount is 0, free the slot */ _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n", *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots); allocator->allocated_slots[*slot_id_p].slot_id = -1; *slot_id_p = -1; allocator->n_used_slots -= 1; if (allocator->n_used_slots == 0) { dbus_free (allocator->allocated_slots); allocator->allocated_slots = NULL; allocator->n_allocated_slots = 0; } _dbus_unlock (allocator->lock); } /** * Initializes a slot list. * @param list the list to initialize. */ void _dbus_data_slot_list_init (DBusDataSlotList *list) { list->slots = NULL; list->n_slots = 0; } /** * Stores a pointer in the data slot list, along with an optional * function to be used for freeing the data when the data is set * again, or when the slot list is finalized. The slot number must * have been allocated with _dbus_data_slot_allocator_alloc() for the * same allocator passed in here. The same allocator has to be used * with the slot list every time. * * @param allocator the allocator to use * @param list the data slot list * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @param old_free_func free function for any previously-existing data * @param old_data previously-existing data, should be freed with old_free_func * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot, void *data, DBusFreeFunction free_data_func, DBusFreeFunction *old_free_func, void **old_data) { #ifndef DBUS_DISABLE_ASSERT /* We need to take the allocator lock here, because the allocator could * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts * are disabled, since then the asserts are empty. */ if (!_dbus_lock (allocator->lock)) _dbus_assert_not_reached ("we should have initialized global locks " "before we allocated this slot"); _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); _dbus_unlock (allocator->lock); #endif if (slot >= list->n_slots) { DBusDataSlot *tmp; int i; tmp = dbus_realloc (list->slots, sizeof (DBusDataSlot) * (slot + 1)); if (tmp == NULL) return FALSE; list->slots = tmp; i = list->n_slots; list->n_slots = slot + 1; while (i < list->n_slots) { list->slots[i].data = NULL; list->slots[i].free_data_func = NULL; ++i; } } _dbus_assert (slot < list->n_slots); *old_data = list->slots[slot].data; *old_free_func = list->slots[slot].free_data_func; list->slots[slot].data = data; list->slots[slot].free_data_func = free_data_func; return TRUE; } /** * Retrieves data previously set with _dbus_data_slot_list_set_data(). * The slot must still be allocated (must not have been freed). * * @param allocator the allocator slot was allocated from * @param list the data slot list * @param slot the slot to get data from * @returns the data, or #NULL if not found */ void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot) { #ifndef DBUS_DISABLE_ASSERT /* We need to take the allocator lock here, because the allocator could * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts * are disabled, since then the asserts are empty. */ if (!_dbus_lock (allocator->lock)) _dbus_assert_not_reached ("we should have initialized global locks " "before we allocated this slot"); _dbus_assert (slot >= 0); _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); _dbus_unlock (allocator->lock); #endif if (slot >= list->n_slots) return NULL; else return list->slots[slot].data; } /** * Frees all data slots contained in the list, calling * application-provided free functions if they exist. * * @param list the list to clear */ void _dbus_data_slot_list_clear (DBusDataSlotList *list) { int i; i = 0; while (i < list->n_slots) { if (list->slots[i].free_data_func) (* list->slots[i].free_data_func) (list->slots[i].data); list->slots[i].data = NULL; list->slots[i].free_data_func = NULL; ++i; } } /** * Frees the data slot list and all data slots contained * in it, calling application-provided free functions * if they exist. * * @param list the list to free */ void _dbus_data_slot_list_free (DBusDataSlotList *list) { _dbus_data_slot_list_clear (list); dbus_free (list->slots); list->slots = NULL; list->n_slots = 0; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include static int free_counter; static void test_free_slot_data_func (void *data) { int i = _DBUS_POINTER_TO_INT (data); _dbus_assert (free_counter == i); ++free_counter; } /** * Test function for data slots */ dbus_bool_t _dbus_data_slot_test (void) { DBusDataSlotAllocator allocator; DBusDataSlotList list; int i; DBusFreeFunction old_free_func; void *old_data; if (!_dbus_data_slot_allocator_init (&allocator, _DBUS_LOCK_server_slots)) _dbus_assert_not_reached ("no memory for allocator"); _dbus_data_slot_list_init (&list); #define N_SLOTS 100 i = 0; while (i < N_SLOTS) { /* we don't really want apps to rely on this ordered * allocation, but it simplifies things to rely on it * here. */ dbus_int32_t tmp = -1; _dbus_data_slot_allocator_alloc (&allocator, &tmp); if (tmp != i) _dbus_assert_not_reached ("did not allocate slots in numeric order\n"); ++i; } i = 0; while (i < N_SLOTS) { if (!_dbus_data_slot_list_set (&allocator, &list, i, _DBUS_INT_TO_POINTER (i), test_free_slot_data_func, &old_free_func, &old_data)) _dbus_assert_not_reached ("no memory to set data"); _dbus_assert (old_free_func == NULL); _dbus_assert (old_data == NULL); _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) == _DBUS_INT_TO_POINTER (i)); ++i; } free_counter = 0; i = 0; while (i < N_SLOTS) { if (!_dbus_data_slot_list_set (&allocator, &list, i, _DBUS_INT_TO_POINTER (i), test_free_slot_data_func, &old_free_func, &old_data)) _dbus_assert_not_reached ("no memory to set data"); _dbus_assert (old_free_func == test_free_slot_data_func); _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i); (* old_free_func) (old_data); _dbus_assert (i == (free_counter - 1)); _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) == _DBUS_INT_TO_POINTER (i)); ++i; } free_counter = 0; _dbus_data_slot_list_free (&list); _dbus_assert (N_SLOTS == free_counter); i = 0; while (i < N_SLOTS) { dbus_int32_t tmp = i; _dbus_data_slot_allocator_free (&allocator, &tmp); _dbus_assert (tmp == -1); ++i; } return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-watch.h0000644000175000017500000001116512602773110015710 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-watch.h DBusWatch internal interfaces * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_WATCH_H #define DBUS_WATCH_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusWatchInternals * @{ */ /* Public methods on DBusWatch are in dbus-connection.h */ typedef struct DBusWatchList DBusWatchList; #define _DBUS_WATCH_NVAL (1<<4) /** function to run when the watch is handled */ typedef dbus_bool_t (* DBusWatchHandler) (DBusWatch *watch, unsigned int flags, void *data); DBUS_PRIVATE_EXPORT DBusWatch* _dbus_watch_new (DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function); DBUS_PRIVATE_EXPORT DBusWatch* _dbus_watch_ref (DBusWatch *watch); DBUS_PRIVATE_EXPORT void _dbus_watch_unref (DBusWatch *watch); DBUS_PRIVATE_EXPORT void _dbus_watch_invalidate (DBusWatch *watch); void _dbus_watch_sanitize_condition (DBusWatch *watch, unsigned int *condition); void _dbus_watch_set_handler (DBusWatch *watch, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function); DBUS_PRIVATE_EXPORT DBusWatchList* _dbus_watch_list_new (void); DBUS_PRIVATE_EXPORT void _dbus_watch_list_free (DBusWatchList *watch_list); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_watch_list_set_functions (DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_watch_list_add_watch (DBusWatchList *watch_list, DBusWatch *watch); DBUS_PRIVATE_EXPORT void _dbus_watch_list_remove_watch (DBusWatchList *watch_list, DBusWatch *watch); void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, DBusWatch *watch, dbus_bool_t enabled); void _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, dbus_bool_t enabled); dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_watch_get_oom_last_time (DBusWatch *watch); DBUS_PRIVATE_EXPORT void _dbus_watch_set_oom_last_time (DBusWatch *watch, dbus_bool_t oom); DBusSocket _dbus_watch_get_socket (DBusWatch *watch); DBUS_PRIVATE_EXPORT DBusPollable _dbus_watch_get_pollable (DBusWatch *watch); /** @} */ DBUS_END_DECLS #endif /* DBUS_WATCH_H */ dbus-1.10.6/dbus/dbus-watch.c0000644000175000017500000005275112602773110015711 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-watch.c DBusWatch implementation * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-watch.h" #include "dbus-list.h" /** * @defgroup DBusWatchInternals DBusWatch implementation details * @ingroup DBusInternals * @brief implementation details for DBusWatch * * @{ */ /** * Implementation of DBusWatch */ struct DBusWatch { int refcount; /**< Reference count */ DBusPollable fd; /**< File descriptor. */ unsigned int flags; /**< Conditions to watch. */ DBusWatchHandler handler; /**< Watch handler. */ void *handler_data; /**< Watch handler data. */ DBusFreeFunction free_handler_data_function; /**< Free the watch handler data. */ void *data; /**< Application data. */ DBusFreeFunction free_data_function; /**< Free the application data. */ unsigned int enabled : 1; /**< Whether it's enabled. */ unsigned int oom_last_time : 1; /**< Whether it was OOM last time. */ }; dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch) { return watch->enabled; } dbus_bool_t _dbus_watch_get_oom_last_time (DBusWatch *watch) { return watch->oom_last_time; } void _dbus_watch_set_oom_last_time (DBusWatch *watch, dbus_bool_t oom) { watch->oom_last_time = oom; } /** * Creates a new DBusWatch. Used to add a file descriptor to be polled * by a main loop. * * @param fd the file descriptor to be watched. * @param flags the conditions to watch for on the descriptor. * @param enabled the initial enabled state * @param handler the handler function * @param data data for handler function * @param free_data_function function to free the data * @returns the new DBusWatch object. */ DBusWatch* _dbus_watch_new (DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function) { DBusWatch *watch; #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); watch = dbus_new0 (DBusWatch, 1); if (watch == NULL) return NULL; watch->refcount = 1; watch->fd = fd; watch->flags = flags; watch->enabled = enabled; watch->handler = handler; watch->handler_data = data; watch->free_handler_data_function = free_data_function; return watch; } /** * Increments the reference count of a DBusWatch object. * * @param watch the watch object. * @returns the watch object. */ DBusWatch * _dbus_watch_ref (DBusWatch *watch) { watch->refcount += 1; return watch; } /** * Decrements the reference count of a DBusWatch object * and finalizes the object if the count reaches zero. * * @param watch the watch object. */ void _dbus_watch_unref (DBusWatch *watch) { _dbus_assert (watch != NULL); _dbus_assert (watch->refcount > 0); watch->refcount -= 1; if (watch->refcount == 0) { if (_dbus_pollable_is_valid (watch->fd)) _dbus_warn ("this watch should have been invalidated"); dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ if (watch->free_handler_data_function) (* watch->free_handler_data_function) (watch->handler_data); dbus_free (watch); } } /** * Clears the file descriptor from a now-invalid watch object so that * no one tries to use it. This is because a watch may stay alive due * to reference counts after the file descriptor is closed. * Invalidation makes it easier to catch bugs. It also * keeps people from doing dorky things like assuming file descriptors * are unique (never recycled). * * @param watch the watch object. */ void _dbus_watch_invalidate (DBusWatch *watch) { _dbus_pollable_invalidate (&watch->fd); watch->flags = 0; } /** * Sanitizes the given condition so that it only contains * flags that the DBusWatch requested. e.g. if the * watch is a DBUS_WATCH_READABLE watch then * DBUS_WATCH_WRITABLE will be stripped from the condition. * * @param watch the watch object. * @param condition address of the condition to sanitize. */ void _dbus_watch_sanitize_condition (DBusWatch *watch, unsigned int *condition) { if (!(watch->flags & DBUS_WATCH_READABLE)) *condition &= ~DBUS_WATCH_READABLE; if (!(watch->flags & DBUS_WATCH_WRITABLE)) *condition &= ~DBUS_WATCH_WRITABLE; } /** * @typedef DBusWatchList * * Opaque data type representing a list of watches * and a set of DBusAddWatchFunction/DBusRemoveWatchFunction. * Automatically handles removing/re-adding watches * when the DBusAddWatchFunction is updated or changed. * Holds a reference count to each watch. * * Used in the implementation of both DBusServer and * DBusClient. * */ /** * DBusWatchList implementation details. All fields * are private. * */ struct DBusWatchList { DBusList *watches; /**< Watch objects. */ DBusAddWatchFunction add_watch_function; /**< Callback for adding a watch. */ DBusRemoveWatchFunction remove_watch_function; /**< Callback for removing a watch. */ DBusWatchToggledFunction watch_toggled_function; /**< Callback on toggling enablement */ void *watch_data; /**< Data for watch callbacks */ DBusFreeFunction watch_free_data_function; /**< Free function for watch callback data */ }; /** * Creates a new watch list. Returns #NULL if insufficient * memory exists. * * @returns the new watch list, or #NULL on failure. */ DBusWatchList* _dbus_watch_list_new (void) { DBusWatchList *watch_list; watch_list = dbus_new0 (DBusWatchList, 1); if (watch_list == NULL) return NULL; return watch_list; } /** * Frees a DBusWatchList. * * @param watch_list the watch list. */ void _dbus_watch_list_free (DBusWatchList *watch_list) { /* free watch_data and removes watches as a side effect */ _dbus_watch_list_set_functions (watch_list, NULL, NULL, NULL, NULL, NULL); _dbus_list_foreach (&watch_list->watches, (DBusForeachFunction) _dbus_watch_unref, NULL); _dbus_list_clear (&watch_list->watches); dbus_free (watch_list); } #ifdef DBUS_ENABLE_VERBOSE_MODE static const char* watch_flags_to_string (int flags) { const char *watch_type; if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) watch_type = "readwrite"; else if (flags & DBUS_WATCH_READABLE) watch_type = "read"; else if (flags & DBUS_WATCH_WRITABLE) watch_type = "write"; else watch_type = "not read or write"; return watch_type; } #endif /* DBUS_ENABLE_VERBOSE_MODE */ /** * Sets the watch functions. This function is the "backend" * for dbus_connection_set_watch_functions() and * dbus_server_set_watch_functions(). * * @param watch_list the watch list. * @param add_function the add watch function. * @param remove_function the remove watch function. * @param toggled_function function on toggling enabled flag, or #NULL * @param data the data for those functions. * @param free_data_function the function to free the data. * @returns #FALSE if not enough memory * */ dbus_bool_t _dbus_watch_list_set_functions (DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { /* Add watches with the new watch function, failing on OOM */ if (add_function != NULL) { DBusList *link; link = _dbus_list_get_first_link (&watch_list->watches); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&watch_list->watches, link); #ifdef DBUS_ENABLE_VERBOSE_MODE DBusWatch *watch = link->data; _dbus_verbose ("Adding a %s watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set add watch function\n", watch_flags_to_string (dbus_watch_get_flags (link->data)), _dbus_pollable_printable (watch->fd)); #endif if (!(* add_function) (link->data, data)) { /* remove it all again and return FALSE */ DBusList *link2; link2 = _dbus_list_get_first_link (&watch_list->watches); while (link2 != link) { DBusList *next = _dbus_list_get_next_link (&watch_list->watches, link2); #ifdef DBUS_ENABLE_VERBOSE_MODE DBusWatch *watch2 = link2->data; _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT " using newly-set remove function because initial add failed\n", _dbus_pollable_printable (watch2->fd)); #endif (* remove_function) (link2->data, data); link2 = next; } return FALSE; } link = next; } } /* Remove all current watches from previous watch handlers */ if (watch_list->remove_watch_function != NULL) { _dbus_verbose ("Removing all pre-existing watches\n"); _dbus_list_foreach (&watch_list->watches, (DBusForeachFunction) watch_list->remove_watch_function, watch_list->watch_data); } if (watch_list->watch_free_data_function != NULL) (* watch_list->watch_free_data_function) (watch_list->watch_data); watch_list->add_watch_function = add_function; watch_list->remove_watch_function = remove_function; watch_list->watch_toggled_function = toggled_function; watch_list->watch_data = data; watch_list->watch_free_data_function = free_data_function; return TRUE; } /** * Adds a new watch to the watch list, invoking the * application DBusAddWatchFunction if appropriate. * * @param watch_list the watch list. * @param watch the watch to add. * @returns #TRUE on success, #FALSE if no memory. */ dbus_bool_t _dbus_watch_list_add_watch (DBusWatchList *watch_list, DBusWatch *watch) { if (!_dbus_list_append (&watch_list->watches, watch)) return FALSE; _dbus_watch_ref (watch); if (watch_list->add_watch_function != NULL) { _dbus_verbose ("Adding watch on fd %" DBUS_POLLABLE_FORMAT "\n", _dbus_pollable_printable (watch->fd)); if (!(* watch_list->add_watch_function) (watch, watch_list->watch_data)) { _dbus_list_remove_last (&watch_list->watches, watch); _dbus_watch_unref (watch); return FALSE; } } return TRUE; } /** * Removes a watch from the watch list, invoking the * application's DBusRemoveWatchFunction if appropriate. * * @param watch_list the watch list. * @param watch the watch to remove. */ void _dbus_watch_list_remove_watch (DBusWatchList *watch_list, DBusWatch *watch) { if (!_dbus_list_remove (&watch_list->watches, watch)) _dbus_assert_not_reached ("Nonexistent watch was removed"); if (watch_list->remove_watch_function != NULL) { _dbus_verbose ("Removing watch on fd %" DBUS_POLLABLE_FORMAT "\n", _dbus_pollable_printable (watch->fd)); (* watch_list->remove_watch_function) (watch, watch_list->watch_data); } _dbus_watch_unref (watch); } /** * Sets a watch to the given enabled state, invoking the * application's DBusWatchToggledFunction if appropriate. * * @param watch_list the watch list. * @param watch the watch to toggle. * @param enabled #TRUE to enable */ void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, DBusWatch *watch, dbus_bool_t enabled) { enabled = !!enabled; if (enabled == watch->enabled) return; watch->enabled = enabled; if (watch_list->watch_toggled_function != NULL) { _dbus_verbose ("Toggling watch %p on fd %" DBUS_POLLABLE_FORMAT " to %d\n", watch, _dbus_pollable_printable (watch->fd), watch->enabled); (* watch_list->watch_toggled_function) (watch, watch_list->watch_data); } } /** * Sets all watches to the given enabled state, invoking the * application's DBusWatchToggledFunction if appropriate. * * @param watch_list the watch list. * @param enabled #TRUE to enable */ void _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, dbus_bool_t enabled) { DBusList *link; for (link = _dbus_list_get_first_link (&watch_list->watches); link != NULL; link = _dbus_list_get_next_link (&watch_list->watches, link)) { _dbus_watch_list_toggle_watch (watch_list, link->data, enabled); } } /** * Sets the handler for the watch. * * @todo this function only exists because of the weird * way connection watches are done, see the note * in docs for _dbus_connection_handle_watch(). * * @param watch the watch * @param handler the new handler * @param data the data * @param free_data_function free data with this */ void _dbus_watch_set_handler (DBusWatch *watch, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function) { if (watch->free_handler_data_function) (* watch->free_handler_data_function) (watch->handler_data); watch->handler = handler; watch->handler_data = data; watch->free_handler_data_function = free_data_function; } /** @} */ /** * @defgroup DBusWatch DBusWatch * @ingroup DBus * @brief Object representing a file descriptor to be watched. * * Types and functions related to DBusWatch. A watch represents * a file descriptor that the main loop needs to monitor, * as in Qt's QSocketNotifier or GLib's g_io_add_watch(). * * Use dbus_connection_set_watch_functions() or dbus_server_set_watch_functions() * to be notified when libdbus needs to add or remove watches. * * @{ */ /** * @typedef DBusWatch * * Opaque object representing a file descriptor * to be watched for changes in readability, * writability, or hangup. */ /** * Deprecated former name of dbus_watch_get_unix_fd(). * * @param watch the DBusWatch object. * @returns the file descriptor to watch. */ int dbus_watch_get_fd (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, -1); return dbus_watch_get_unix_fd(watch); } /** * Returns a UNIX file descriptor to be watched, * which may be a pipe, socket, or other type of * descriptor. On UNIX this is preferred to * dbus_watch_get_socket() since it works with * more kinds of #DBusWatch. * * Always returns -1 on Windows. On Windows you use * dbus_watch_get_socket() to get a Winsock socket to watch. * * @param watch the DBusWatch object. * @returns the file descriptor to watch. */ int dbus_watch_get_unix_fd (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, -1); /* FIXME remove #ifdef and do this on a lower level * (watch should have set_socket and set_unix_fd and track * which it has, and the transport should provide the * appropriate watch type) */ #ifdef DBUS_UNIX return watch->fd; #else return dbus_watch_get_socket( watch ); #endif } /** * Returns a socket to be watched, on UNIX this will return -1 if our * transport is not socket-based so dbus_watch_get_unix_fd() is * preferred. * * On Windows, dbus_watch_get_unix_fd() returns -1 but this function * returns a Winsock socket (assuming the transport is socket-based, * as it always is for now). * * @param watch the DBusWatch object. * @returns the socket to watch. */ int dbus_watch_get_socket (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, -1); #ifdef DBUS_UNIX return watch->fd; #else return _dbus_socket_get_int (watch->fd); #endif } DBusSocket _dbus_watch_get_socket (DBusWatch *watch) { DBusSocket s; _dbus_assert (watch != NULL); #ifdef DBUS_UNIX s.fd = watch->fd; #else s = watch->fd; #endif return s; } DBusPollable _dbus_watch_get_pollable (DBusWatch *watch) { _dbus_assert (watch != NULL); return watch->fd; } /** * Gets flags from DBusWatchFlags indicating * what conditions should be monitored on the * file descriptor. * * The flags returned will only contain DBUS_WATCH_READABLE * and DBUS_WATCH_WRITABLE, never DBUS_WATCH_HANGUP or * DBUS_WATCH_ERROR; all watches implicitly include a watch * for hangups, errors, and other exceptional conditions. * * @param watch the DBusWatch object. * @returns the conditions to watch. */ unsigned int dbus_watch_get_flags (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, 0); _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); return watch->flags; } /** * Gets data previously set with dbus_watch_set_data() * or #NULL if none. * * @param watch the DBusWatch object. * @returns previously-set data. */ void* dbus_watch_get_data (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, NULL); return watch->data; } /** * Sets data which can be retrieved with dbus_watch_get_data(). * Intended for use by the DBusAddWatchFunction and * DBusRemoveWatchFunction to store their own data. For example with * Qt you might store the QSocketNotifier for this watch and with GLib * you might store a GSource. * * @param watch the DBusWatch object. * @param data the data. * @param free_data_function function to be called to free the data. */ void dbus_watch_set_data (DBusWatch *watch, void *data, DBusFreeFunction free_data_function) { _dbus_return_if_fail (watch != NULL); _dbus_verbose ("Setting watch fd %" DBUS_POLLABLE_FORMAT " data to data = %p function = %p from data = %p function = %p\n", _dbus_pollable_printable (watch->fd), data, free_data_function, watch->data, watch->free_data_function); if (watch->free_data_function != NULL) (* watch->free_data_function) (watch->data); watch->data = data; watch->free_data_function = free_data_function; } /** * Returns whether a watch is enabled or not. If not * enabled, it should not be polled by the main loop. * * @param watch the DBusWatch object * @returns #TRUE if the watch is enabled */ dbus_bool_t dbus_watch_get_enabled (DBusWatch *watch) { _dbus_return_val_if_fail (watch != NULL, FALSE); return watch->enabled; } /** * Called to notify the D-Bus library when a previously-added watch is * ready for reading or writing, or has an exception such as a hangup. * * If this function returns #FALSE, then the file descriptor may still * be ready for reading or writing, but more memory is needed in order * to do the reading or writing. If you ignore the #FALSE return, your * application may spin in a busy loop on the file descriptor until * memory becomes available, but nothing more catastrophic should * happen. * * dbus_watch_handle() cannot be called during the * DBusAddWatchFunction, as the connection will not be ready to handle * that watch yet. * * It is not allowed to reference a DBusWatch after it has been passed * to remove_function. * * @param watch the DBusWatch object. * @param flags the poll condition using #DBusWatchFlags values * @returns #FALSE if there wasn't enough memory */ dbus_bool_t dbus_watch_handle (DBusWatch *watch, unsigned int flags) { _dbus_return_val_if_fail (watch != NULL, FALSE); #ifndef DBUS_DISABLE_CHECKS if (!_dbus_pollable_is_valid (watch->fd) || watch->flags == 0) { _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n"); return TRUE; } #endif _dbus_return_val_if_fail (_dbus_pollable_is_valid (watch->fd) /* fails if watch was removed */, TRUE); _dbus_watch_sanitize_condition (watch, &flags); if (flags == 0) { _dbus_verbose ("After sanitization, watch flags on fd %" DBUS_POLLABLE_FORMAT " were 0\n", _dbus_pollable_printable (watch->fd)); return TRUE; } else return (* watch->handler) (watch, flags, watch->handler_data); } /** @} */ dbus-1.10.6/dbus/dbus-transport-socket.h0000644000175000017500000000407512602773110020126 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-socket.h Socket subclasses of DBusTransport * * Copyright (C) 2002, 2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TRANSPORT_SOCKET_H #define DBUS_TRANSPORT_SOCKET_H #include DBUS_BEGIN_DECLS DBusTransport* _dbus_transport_new_for_socket (DBusSocket fd, const DBusString *server_guid, const DBusString *address); DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error); DBusTransportOpenResult _dbus_transport_open_socket (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error); DBUS_END_DECLS #endif /* DBUS_TRANSPORT_SOCKET_H */ dbus-1.10.6/dbus/dbus-transport-socket.c0000644000175000017500000013737112602773110020127 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-socket.c Socket subclasses of DBusTransport * * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-nonce.h" #include "dbus-transport-socket.h" #include "dbus-transport-protected.h" #include "dbus-watch.h" #include "dbus-credentials.h" /** * @defgroup DBusTransportSocket DBusTransport implementations for sockets * @ingroup DBusInternals * @brief Implementation details of DBusTransport on sockets * * @{ */ /** * Opaque object representing a socket file descriptor transport. */ typedef struct DBusTransportSocket DBusTransportSocket; /** * Implementation details of DBusTransportSocket. All members are private. */ struct DBusTransportSocket { DBusTransport base; /**< Parent instance */ DBusSocket fd; /**< File descriptor. */ DBusWatch *read_watch; /**< Watch for readability. */ DBusWatch *write_watch; /**< Watch for writability. */ int max_bytes_read_per_iteration; /**< To avoid blocking too long. */ int max_bytes_written_per_iteration; /**< To avoid blocking too long. */ int message_bytes_written; /**< Number of bytes of current * outgoing message that have * been written. */ DBusString encoded_outgoing; /**< Encoded version of current * outgoing message. */ DBusString encoded_incoming; /**< Encoded version of current * incoming data. */ }; static void free_watches (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_verbose ("start\n"); if (socket_transport->read_watch) { if (transport->connection) _dbus_connection_remove_watch_unlocked (transport->connection, socket_transport->read_watch); _dbus_watch_invalidate (socket_transport->read_watch); _dbus_watch_unref (socket_transport->read_watch); socket_transport->read_watch = NULL; } if (socket_transport->write_watch) { if (transport->connection) _dbus_connection_remove_watch_unlocked (transport->connection, socket_transport->write_watch); _dbus_watch_invalidate (socket_transport->write_watch); _dbus_watch_unref (socket_transport->write_watch); socket_transport->write_watch = NULL; } _dbus_verbose ("end\n"); } static void socket_finalize (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_verbose ("\n"); free_watches (transport); _dbus_string_free (&socket_transport->encoded_outgoing); _dbus_string_free (&socket_transport->encoded_incoming); _dbus_transport_finalize_base (transport); _dbus_assert (socket_transport->read_watch == NULL); _dbus_assert (socket_transport->write_watch == NULL); dbus_free (transport); } static void check_write_watch (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; dbus_bool_t needed; if (transport->connection == NULL) return; if (transport->disconnected) { _dbus_assert (socket_transport->write_watch == NULL); return; } _dbus_transport_ref (transport); if (_dbus_transport_try_to_authenticate (transport)) needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); else { if (transport->send_credentials_pending) needed = TRUE; else { DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); /* If we need memory we install the write watch just in case, * if there's no need for it, it will get de-installed * next time we try reading. */ if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) needed = TRUE; else needed = FALSE; } } _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %" DBUS_SOCKET_FORMAT " outgoing messages exist %d\n", needed, transport->connection, socket_transport->write_watch, _dbus_socket_printable (socket_transport->fd), _dbus_connection_has_messages_to_send_unlocked (transport->connection)); _dbus_connection_toggle_watch_unlocked (transport->connection, socket_transport->write_watch, needed); _dbus_transport_unref (transport); } static void check_read_watch (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; dbus_bool_t need_read_watch; _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n", _dbus_socket_printable (socket_transport->fd)); if (transport->connection == NULL) return; if (transport->disconnected) { _dbus_assert (socket_transport->read_watch == NULL); return; } _dbus_transport_ref (transport); if (_dbus_transport_try_to_authenticate (transport)) need_read_watch = (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) && (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds); else { if (transport->receive_credentials_pending) need_read_watch = TRUE; else { /* The reason to disable need_read_watch when not WAITING_FOR_INPUT * is to avoid spinning on the file descriptor when we're waiting * to write or for some other part of the auth process */ DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); /* If we need memory we install the read watch just in case, * if there's no need for it, it will get de-installed * next time we try reading. If we're authenticated we * install it since we normally have it installed while * authenticated. */ if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || auth_state == DBUS_AUTH_STATE_AUTHENTICATED) need_read_watch = TRUE; else need_read_watch = FALSE; } } _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch); _dbus_connection_toggle_watch_unlocked (transport->connection, socket_transport->read_watch, need_read_watch); _dbus_transport_unref (transport); } static void do_io_error (DBusTransport *transport) { _dbus_transport_ref (transport); _dbus_transport_disconnect (transport); _dbus_transport_unref (transport); } /* return value is whether we successfully read any new data. */ static dbus_bool_t read_data_into_auth (DBusTransport *transport, dbus_bool_t *oom) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusString *buffer; int bytes_read; int saved_errno; *oom = FALSE; _dbus_auth_get_buffer (transport->auth, &buffer); bytes_read = _dbus_read_socket (socket_transport->fd, buffer, socket_transport->max_bytes_read_per_iteration); saved_errno = _dbus_save_socket_errno (); _dbus_auth_return_buffer (transport->auth, buffer); if (bytes_read > 0) { _dbus_verbose (" read %d bytes in auth phase\n", bytes_read); return TRUE; } else if (bytes_read < 0) { /* EINTR already handled for us */ if (_dbus_get_is_errno_enomem (saved_errno)) { *oom = TRUE; } else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) ; /* do nothing, just return FALSE below */ else { _dbus_verbose ("Error reading from remote app: %s\n", _dbus_strerror (saved_errno)); do_io_error (transport); } return FALSE; } else { _dbus_assert (bytes_read == 0); _dbus_verbose ("Disconnected from remote app\n"); do_io_error (transport); return FALSE; } } /* Return value is whether we successfully wrote any bytes */ static dbus_bool_t write_data_from_auth (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; int bytes_written; int saved_errno; const DBusString *buffer; if (!_dbus_auth_get_bytes_to_send (transport->auth, &buffer)) return FALSE; bytes_written = _dbus_write_socket (socket_transport->fd, buffer, 0, _dbus_string_get_length (buffer)); saved_errno = _dbus_save_socket_errno (); if (bytes_written > 0) { _dbus_auth_bytes_sent (transport->auth, bytes_written); return TRUE; } else if (bytes_written < 0) { /* EINTR already handled for us */ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) ; else { _dbus_verbose ("Error writing to remote app: %s\n", _dbus_strerror (saved_errno)); do_io_error (transport); } } return FALSE; } /* FALSE on OOM */ static dbus_bool_t exchange_credentials (DBusTransport *transport, dbus_bool_t do_reading, dbus_bool_t do_writing) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusError error = DBUS_ERROR_INIT; _dbus_verbose ("exchange_credentials: do_reading = %d, do_writing = %d\n", do_reading, do_writing); if (do_writing && transport->send_credentials_pending) { if (_dbus_send_credentials_socket (socket_transport->fd, &error)) { transport->send_credentials_pending = FALSE; } else { _dbus_verbose ("Failed to write credentials: %s\n", error.message); dbus_error_free (&error); do_io_error (transport); } } if (do_reading && transport->receive_credentials_pending) { /* FIXME this can fail due to IO error _or_ OOM, broken * (somewhat tricky to fix since the OOM error can be set after * we already read the credentials byte, so basically we need to * separate reading the byte and storing it in the * transport->credentials). Does not really matter for now * because storing in credentials never actually fails on unix. */ if (_dbus_read_credentials_socket (socket_transport->fd, transport->credentials, &error)) { transport->receive_credentials_pending = FALSE; } else { _dbus_verbose ("Failed to read credentials %s\n", error.message); dbus_error_free (&error); do_io_error (transport); } } if (!(transport->send_credentials_pending || transport->receive_credentials_pending)) { if (!_dbus_auth_set_credentials (transport->auth, transport->credentials)) return FALSE; } return TRUE; } static dbus_bool_t do_authentication (DBusTransport *transport, dbus_bool_t do_reading, dbus_bool_t do_writing, dbus_bool_t *auth_completed) { dbus_bool_t oom; dbus_bool_t orig_auth_state; oom = FALSE; orig_auth_state = _dbus_transport_try_to_authenticate (transport); /* This is essential to avoid the check_write_watch() at the end, * we don't want to add a write watch in do_iteration before * we try writing and get EAGAIN */ if (orig_auth_state) { if (auth_completed) *auth_completed = FALSE; return TRUE; } _dbus_transport_ref (transport); while (!_dbus_transport_try_to_authenticate (transport) && _dbus_transport_get_is_connected (transport)) { if (!exchange_credentials (transport, do_reading, do_writing)) { /* OOM */ oom = TRUE; goto out; } if (transport->send_credentials_pending || transport->receive_credentials_pending) { _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n", transport->send_credentials_pending, transport->receive_credentials_pending); goto out; } #define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client") switch (_dbus_auth_do_work (transport->auth)) { case DBUS_AUTH_STATE_WAITING_FOR_INPUT: _dbus_verbose (" %s auth state: waiting for input\n", TRANSPORT_SIDE (transport)); if (!do_reading || !read_data_into_auth (transport, &oom)) goto out; break; case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: _dbus_verbose (" %s auth state: waiting for memory\n", TRANSPORT_SIDE (transport)); oom = TRUE; goto out; break; case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: _dbus_verbose (" %s auth state: bytes to send\n", TRANSPORT_SIDE (transport)); if (!do_writing || !write_data_from_auth (transport)) goto out; break; case DBUS_AUTH_STATE_NEED_DISCONNECT: _dbus_verbose (" %s auth state: need to disconnect\n", TRANSPORT_SIDE (transport)); do_io_error (transport); break; case DBUS_AUTH_STATE_AUTHENTICATED: _dbus_verbose (" %s auth state: authenticated\n", TRANSPORT_SIDE (transport)); break; } } out: if (auth_completed) *auth_completed = (orig_auth_state != _dbus_transport_try_to_authenticate (transport)); check_read_watch (transport); check_write_watch (transport); _dbus_transport_unref (transport); if (oom) return FALSE; else return TRUE; } /* returns false on oom */ static dbus_bool_t do_writing (DBusTransport *transport) { int total; DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; dbus_bool_t oom; /* No messages without authentication! */ if (!_dbus_transport_try_to_authenticate (transport)) { _dbus_verbose ("Not authenticated, not writing anything\n"); return TRUE; } if (transport->disconnected) { _dbus_verbose ("Not connected, not writing anything\n"); return TRUE; } #if 1 _dbus_verbose ("do_writing(), have_messages = %d, fd = %" DBUS_SOCKET_FORMAT "\n", _dbus_connection_has_messages_to_send_unlocked (transport->connection), _dbus_socket_printable (socket_transport->fd)); #endif oom = FALSE; total = 0; while (!transport->disconnected && _dbus_connection_has_messages_to_send_unlocked (transport->connection)) { int bytes_written; DBusMessage *message; const DBusString *header; const DBusString *body; int header_len, body_len; int total_bytes_to_write; int saved_errno; if (total > socket_transport->max_bytes_written_per_iteration) { _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n", total, socket_transport->max_bytes_written_per_iteration); goto out; } message = _dbus_connection_get_message_to_send (transport->connection); _dbus_assert (message != NULL); dbus_message_lock (message); #if 0 _dbus_verbose ("writing message %p\n", message); #endif _dbus_message_get_network_data (message, &header, &body); header_len = _dbus_string_get_length (header); body_len = _dbus_string_get_length (body); if (_dbus_auth_needs_encoding (transport->auth)) { /* Does fd passing even make sense with encoded data? */ _dbus_assert(!DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport)); if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0) { if (!_dbus_auth_encode_data (transport->auth, header, &socket_transport->encoded_outgoing)) { oom = TRUE; goto out; } if (!_dbus_auth_encode_data (transport->auth, body, &socket_transport->encoded_outgoing)) { _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); oom = TRUE; goto out; } } total_bytes_to_write = _dbus_string_get_length (&socket_transport->encoded_outgoing); #if 0 _dbus_verbose ("encoded message is %d bytes\n", total_bytes_to_write); #endif bytes_written = _dbus_write_socket (socket_transport->fd, &socket_transport->encoded_outgoing, socket_transport->message_bytes_written, total_bytes_to_write - socket_transport->message_bytes_written); saved_errno = _dbus_save_socket_errno (); } else { total_bytes_to_write = header_len + body_len; #if 0 _dbus_verbose ("message is %d bytes\n", total_bytes_to_write); #endif #ifdef HAVE_UNIX_FD_PASSING if (socket_transport->message_bytes_written <= 0 && DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport)) { /* Send the fds along with the first byte of the message */ const int *unix_fds; unsigned n; _dbus_message_get_unix_fds(message, &unix_fds, &n); bytes_written = _dbus_write_socket_with_unix_fds_two (socket_transport->fd, header, socket_transport->message_bytes_written, header_len - socket_transport->message_bytes_written, body, 0, body_len, unix_fds, n); saved_errno = _dbus_save_socket_errno (); if (bytes_written > 0 && n > 0) _dbus_verbose("Wrote %i unix fds\n", n); } else #endif { if (socket_transport->message_bytes_written < header_len) { bytes_written = _dbus_write_socket_two (socket_transport->fd, header, socket_transport->message_bytes_written, header_len - socket_transport->message_bytes_written, body, 0, body_len); } else { bytes_written = _dbus_write_socket (socket_transport->fd, body, (socket_transport->message_bytes_written - header_len), body_len - (socket_transport->message_bytes_written - header_len)); } saved_errno = _dbus_save_socket_errno (); } } if (bytes_written < 0) { /* EINTR already handled for us */ /* If the other end closed the socket with close() or shutdown(), we * receive EPIPE here but we must not close the socket yet: there * might still be some data to read. See: * http://lists.freedesktop.org/archives/dbus/2008-March/009526.html */ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno) || _dbus_get_is_errno_epipe (saved_errno)) goto out; /* Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg() * on Unix sockets returns -1 errno=ETOOMANYREFS when the passfd * mechanism (SCM_RIGHTS) is used recursively with a recursion level * of maximum 4. The kernel does not have an API to check whether * the passed fds can be forwarded and it can change asynchronously. * See: * https://bugs.freedesktop.org/show_bug.cgi?id=80163 */ else if (_dbus_get_is_errno_etoomanyrefs (saved_errno)) { /* We only send fds in the first byte of the message. * ETOOMANYREFS cannot happen after. */ _dbus_assert (socket_transport->message_bytes_written == 0); _dbus_verbose (" discard message of %d bytes due to ETOOMANYREFS\n", total_bytes_to_write); socket_transport->message_bytes_written = 0; _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); _dbus_string_compact (&socket_transport->encoded_outgoing, 2048); /* The message was not actually sent but it needs to be removed * from the outgoing queue */ _dbus_connection_message_sent_unlocked (transport->connection, message); } else { _dbus_verbose ("Error writing to remote app: %s\n", _dbus_strerror (saved_errno)); do_io_error (transport); goto out; } } else { _dbus_verbose (" wrote %d bytes of %d\n", bytes_written, total_bytes_to_write); total += bytes_written; socket_transport->message_bytes_written += bytes_written; _dbus_assert (socket_transport->message_bytes_written <= total_bytes_to_write); if (socket_transport->message_bytes_written == total_bytes_to_write) { socket_transport->message_bytes_written = 0; _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); _dbus_string_compact (&socket_transport->encoded_outgoing, 2048); _dbus_connection_message_sent_unlocked (transport->connection, message); } } } out: if (oom) return FALSE; else return TRUE; } /* returns false on out-of-memory */ static dbus_bool_t do_reading (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusString *buffer; int bytes_read; int total; dbus_bool_t oom; int saved_errno; _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n", _dbus_socket_printable (socket_transport->fd)); /* No messages without authentication! */ if (!_dbus_transport_try_to_authenticate (transport)) return TRUE; oom = FALSE; total = 0; again: /* See if we've exceeded max messages and need to disable reading */ check_read_watch (transport); if (total > socket_transport->max_bytes_read_per_iteration) { _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n", total, socket_transport->max_bytes_read_per_iteration); goto out; } _dbus_assert (socket_transport->read_watch != NULL || transport->disconnected); if (transport->disconnected) goto out; if (!dbus_watch_get_enabled (socket_transport->read_watch)) return TRUE; if (_dbus_auth_needs_decoding (transport->auth)) { /* Does fd passing even make sense with encoded data? */ _dbus_assert(!DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport)); if (_dbus_string_get_length (&socket_transport->encoded_incoming) > 0) bytes_read = _dbus_string_get_length (&socket_transport->encoded_incoming); else bytes_read = _dbus_read_socket (socket_transport->fd, &socket_transport->encoded_incoming, socket_transport->max_bytes_read_per_iteration); saved_errno = _dbus_save_socket_errno (); _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) == bytes_read); if (bytes_read > 0) { _dbus_message_loader_get_buffer (transport->loader, &buffer); if (!_dbus_auth_decode_data (transport->auth, &socket_transport->encoded_incoming, buffer)) { _dbus_verbose ("Out of memory decoding incoming data\n"); _dbus_message_loader_return_buffer (transport->loader, buffer); oom = TRUE; goto out; } _dbus_message_loader_return_buffer (transport->loader, buffer); _dbus_string_set_length (&socket_transport->encoded_incoming, 0); _dbus_string_compact (&socket_transport->encoded_incoming, 2048); } } else { _dbus_message_loader_get_buffer (transport->loader, &buffer); #ifdef HAVE_UNIX_FD_PASSING if (DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport)) { int *fds, n_fds; if (!_dbus_message_loader_get_unix_fds(transport->loader, &fds, &n_fds)) { _dbus_verbose ("Out of memory reading file descriptors\n"); _dbus_message_loader_return_buffer (transport->loader, buffer); oom = TRUE; goto out; } bytes_read = _dbus_read_socket_with_unix_fds(socket_transport->fd, buffer, socket_transport->max_bytes_read_per_iteration, fds, &n_fds); saved_errno = _dbus_save_socket_errno (); if (bytes_read >= 0 && n_fds > 0) _dbus_verbose("Read %i unix fds\n", n_fds); _dbus_message_loader_return_unix_fds(transport->loader, fds, bytes_read < 0 ? 0 : n_fds); } else #endif { bytes_read = _dbus_read_socket (socket_transport->fd, buffer, socket_transport->max_bytes_read_per_iteration); saved_errno = _dbus_save_socket_errno (); } _dbus_message_loader_return_buffer (transport->loader, buffer); } if (bytes_read < 0) { /* EINTR already handled for us */ if (_dbus_get_is_errno_enomem (saved_errno)) { _dbus_verbose ("Out of memory in read()/do_reading()\n"); oom = TRUE; goto out; } else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) goto out; else { _dbus_verbose ("Error reading from remote app: %s\n", _dbus_strerror (saved_errno)); do_io_error (transport); goto out; } } else if (bytes_read == 0) { _dbus_verbose ("Disconnected from remote app\n"); do_io_error (transport); goto out; } else { _dbus_verbose (" read %d bytes\n", bytes_read); total += bytes_read; if (!_dbus_transport_queue_messages (transport)) { oom = TRUE; _dbus_verbose (" out of memory when queueing messages we just read in the transport\n"); goto out; } /* Try reading more data until we get EAGAIN and return, or * exceed max bytes per iteration. If in blocking mode of * course we'll block instead of returning. */ goto again; } out: if (oom) return FALSE; else return TRUE; } static dbus_bool_t unix_error_with_read_to_come (DBusTransport *itransport, DBusWatch *watch, unsigned int flags) { DBusTransportSocket *transport = (DBusTransportSocket *) itransport; if (!(flags & DBUS_WATCH_HANGUP || flags & DBUS_WATCH_ERROR)) return FALSE; /* If we have a read watch enabled ... we -might have data incoming ... => handle the HANGUP there */ if (watch != transport->read_watch && _dbus_watch_get_enabled (transport->read_watch)) return FALSE; return TRUE; } static dbus_bool_t socket_handle_watch (DBusTransport *transport, DBusWatch *watch, unsigned int flags) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_assert (watch == socket_transport->read_watch || watch == socket_transport->write_watch); _dbus_assert (watch != NULL); /* If we hit an error here on a write watch, don't disconnect the transport yet because data can * still be in the buffer and do_reading may need several iteration to read * it all (because of its max_bytes_read_per_iteration limit). */ if (!(flags & DBUS_WATCH_READABLE) && unix_error_with_read_to_come (transport, watch, flags)) { _dbus_verbose ("Hang up or error on watch\n"); _dbus_transport_disconnect (transport); return TRUE; } if (watch == socket_transport->read_watch && (flags & DBUS_WATCH_READABLE)) { dbus_bool_t auth_finished; #if 1 _dbus_verbose ("handling read watch %p flags = %x\n", watch, flags); #endif if (!do_authentication (transport, TRUE, FALSE, &auth_finished)) return FALSE; /* We don't want to do a read immediately following * a successful authentication. This is so we * have a chance to propagate the authentication * state further up. Specifically, we need to * process any pending data from the auth object. */ if (!auth_finished) { if (!do_reading (transport)) { _dbus_verbose ("no memory to read\n"); return FALSE; } } else { _dbus_verbose ("Not reading anything since we just completed the authentication\n"); } } else if (watch == socket_transport->write_watch && (flags & DBUS_WATCH_WRITABLE)) { #if 1 _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n", _dbus_connection_has_messages_to_send_unlocked (transport->connection)); #endif if (!do_authentication (transport, FALSE, TRUE, NULL)) return FALSE; if (!do_writing (transport)) { _dbus_verbose ("no memory to write\n"); return FALSE; } /* See if we still need the write watch */ check_write_watch (transport); } #ifdef DBUS_ENABLE_VERBOSE_MODE else { if (watch == socket_transport->read_watch) _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n", flags); else if (watch == socket_transport->write_watch) _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n", flags); else _dbus_verbose ("asked to handle watch %p on fd %" DBUS_SOCKET_FORMAT " that we don't recognize\n", watch, dbus_watch_get_socket (watch)); } #endif /* DBUS_ENABLE_VERBOSE_MODE */ return TRUE; } static void socket_disconnect (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_verbose ("\n"); free_watches (transport); _dbus_close_socket (socket_transport->fd, NULL); _dbus_socket_invalidate (&socket_transport->fd); } static dbus_bool_t socket_connection_set (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_watch_set_handler (socket_transport->write_watch, _dbus_connection_handle_watch, transport->connection, NULL); _dbus_watch_set_handler (socket_transport->read_watch, _dbus_connection_handle_watch, transport->connection, NULL); if (!_dbus_connection_add_watch_unlocked (transport->connection, socket_transport->write_watch)) return FALSE; if (!_dbus_connection_add_watch_unlocked (transport->connection, socket_transport->read_watch)) { _dbus_connection_remove_watch_unlocked (transport->connection, socket_transport->write_watch); return FALSE; } check_read_watch (transport); check_write_watch (transport); return TRUE; } /** * @todo We need to have a way to wake up the select sleep if * a new iteration request comes in with a flag (read/write) that * we're not currently serving. Otherwise a call that just reads * could block a write call forever (if there are no incoming * messages). */ static void socket_do_iteration (DBusTransport *transport, unsigned int flags, int timeout_milliseconds) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusPollFD poll_fd; int poll_res; int poll_timeout; _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %" DBUS_SOCKET_FORMAT "\n", flags & DBUS_ITERATION_DO_READING ? "read" : "", flags & DBUS_ITERATION_DO_WRITING ? "write" : "", timeout_milliseconds, socket_transport->read_watch, socket_transport->write_watch, _dbus_socket_printable (socket_transport->fd)); /* the passed in DO_READING/DO_WRITING flags indicate whether to * read/write messages, but regardless of those we may need to block * for reading/writing to do auth. But if we do reading for auth, * we don't want to read any messages yet if not given DO_READING. */ poll_fd.fd = _dbus_socket_get_pollable (socket_transport->fd); poll_fd.events = 0; if (_dbus_transport_try_to_authenticate (transport)) { /* This is kind of a hack; if we have stuff to write, then try * to avoid the poll. This is probably about a 5% speedup on an * echo client/server. * * If both reading and writing were requested, we want to avoid this * since it could have funky effects: * - both ends spinning waiting for the other one to read * data so they can finish writing * - prioritizing all writing ahead of reading */ if ((flags & DBUS_ITERATION_DO_WRITING) && !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) && !transport->disconnected && _dbus_connection_has_messages_to_send_unlocked (transport->connection)) { do_writing (transport); if (transport->disconnected || !_dbus_connection_has_messages_to_send_unlocked (transport->connection)) goto out; } /* If we get here, we decided to do the poll() after all */ _dbus_assert (socket_transport->read_watch); if (flags & DBUS_ITERATION_DO_READING) poll_fd.events |= _DBUS_POLLIN; _dbus_assert (socket_transport->write_watch); if (flags & DBUS_ITERATION_DO_WRITING) poll_fd.events |= _DBUS_POLLOUT; } else { DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); if (transport->receive_credentials_pending || auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT) poll_fd.events |= _DBUS_POLLIN; if (transport->send_credentials_pending || auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) poll_fd.events |= _DBUS_POLLOUT; } if (poll_fd.events) { int saved_errno; if (flags & DBUS_ITERATION_BLOCK) poll_timeout = timeout_milliseconds; else poll_timeout = 0; /* For blocking selects we drop the connection lock here * to avoid blocking out connection access during a potentially * indefinite blocking call. The io path is still protected * by the io_path_cond condvar, so we won't reenter this. */ if (flags & DBUS_ITERATION_BLOCK) { _dbus_verbose ("unlock pre poll\n"); _dbus_connection_unlock (transport->connection); } again: poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); saved_errno = _dbus_save_socket_errno (); if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno)) goto again; if (flags & DBUS_ITERATION_BLOCK) { _dbus_verbose ("lock post poll\n"); _dbus_connection_lock (transport->connection); } if (poll_res >= 0) { if (poll_res == 0) poll_fd.revents = 0; /* some concern that posix does not guarantee this; * valgrind flags it as an error. though it probably * is guaranteed on linux at least. */ if (poll_fd.revents & _DBUS_POLLERR) do_io_error (transport); else { dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0; dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0; dbus_bool_t authentication_completed; _dbus_verbose ("in iteration, need_read=%d need_write=%d\n", need_read, need_write); do_authentication (transport, need_read, need_write, &authentication_completed); /* See comment in socket_handle_watch. */ if (authentication_completed) goto out; if (need_read && (flags & DBUS_ITERATION_DO_READING)) do_reading (transport); if (need_write && (flags & DBUS_ITERATION_DO_WRITING)) do_writing (transport); } } else { _dbus_verbose ("Error from _dbus_poll(): %s\n", _dbus_strerror (saved_errno)); } } out: /* We need to install the write watch only if we did not * successfully write everything. Note we need to be careful that we * don't call check_write_watch *before* do_writing, since it's * inefficient to add the write watch, and we can avoid it most of * the time since we can write immediately. * * However, we MUST always call check_write_watch(); DBusConnection code * relies on the fact that running an iteration will notice that * messages are pending. */ check_write_watch (transport); _dbus_verbose (" ... leaving do_iteration()\n"); } static void socket_live_messages_changed (DBusTransport *transport) { /* See if we should look for incoming messages again */ check_read_watch (transport); } static dbus_bool_t socket_get_socket_fd (DBusTransport *transport, DBusSocket *fd_p) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; *fd_p = socket_transport->fd; return TRUE; } static const DBusTransportVTable socket_vtable = { socket_finalize, socket_handle_watch, socket_disconnect, socket_connection_set, socket_do_iteration, socket_live_messages_changed, socket_get_socket_fd }; /** * Creates a new transport for the given socket file descriptor. The file * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to * make it so). This function is shared by various transports that * boil down to a full duplex file descriptor. * * @param fd the file descriptor. * @param server_guid non-#NULL if this transport is on the server side of a connection * @param address the transport's address * @returns the new transport, or #NULL if no memory. */ DBusTransport* _dbus_transport_new_for_socket (DBusSocket fd, const DBusString *server_guid, const DBusString *address) { DBusTransportSocket *socket_transport; socket_transport = dbus_new0 (DBusTransportSocket, 1); if (socket_transport == NULL) return NULL; if (!_dbus_string_init (&socket_transport->encoded_outgoing)) goto failed_0; if (!_dbus_string_init (&socket_transport->encoded_incoming)) goto failed_1; socket_transport->write_watch = _dbus_watch_new (_dbus_socket_get_pollable (fd), DBUS_WATCH_WRITABLE, FALSE, NULL, NULL, NULL); if (socket_transport->write_watch == NULL) goto failed_2; socket_transport->read_watch = _dbus_watch_new (_dbus_socket_get_pollable (fd), DBUS_WATCH_READABLE, FALSE, NULL, NULL, NULL); if (socket_transport->read_watch == NULL) goto failed_3; if (!_dbus_transport_init_base (&socket_transport->base, &socket_vtable, server_guid, address)) goto failed_4; #ifdef HAVE_UNIX_FD_PASSING _dbus_auth_set_unix_fd_possible(socket_transport->base.auth, _dbus_socket_can_pass_unix_fd(fd)); #endif socket_transport->fd = fd; socket_transport->message_bytes_written = 0; /* These values should probably be tunable or something. */ socket_transport->max_bytes_read_per_iteration = 2048; socket_transport->max_bytes_written_per_iteration = 2048; return (DBusTransport*) socket_transport; failed_4: _dbus_watch_invalidate (socket_transport->read_watch); _dbus_watch_unref (socket_transport->read_watch); failed_3: _dbus_watch_invalidate (socket_transport->write_watch); _dbus_watch_unref (socket_transport->write_watch); failed_2: _dbus_string_free (&socket_transport->encoded_incoming); failed_1: _dbus_string_free (&socket_transport->encoded_outgoing); failed_0: dbus_free (socket_transport); return NULL; } /** * Creates a new transport for the given hostname and port. * If host is NULL, it will default to localhost * * @param host the host to connect to * @param port the port to connect to * @param family the address family to connect to * @param noncefile path to nonce file * @param error location to store reason for failure. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error) { DBusSocket fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (host == NULL) host = "localhost"; if (!_dbus_string_append (&address, noncefile ? "nonce-tcp:" : "tcp:")) goto error; if (!_dbus_string_append (&address, "host=") || !_dbus_string_append (&address, host)) goto error; if (!_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, port)) goto error; if (family != NULL && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) goto error; if (noncefile != NULL && (!_dbus_string_append (&address, ",noncefile=") || !_dbus_string_append (&address, noncefile))) goto error; fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error); if (!_dbus_socket_is_valid (fd)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&address); return NULL; } _dbus_verbose ("Successfully connected to tcp socket %s:%s\n", host, port); transport = _dbus_transport_new_for_socket (fd, NULL, &address); _dbus_string_free (&address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_close_socket (fd, NULL); _dbus_socket_invalidate (&fd); } return transport; error: _dbus_string_free (&address); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } /** * Opens a TCP socket transport. * * @param entry the address entry to try opening as a tcp transport. * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_socket(DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; dbus_bool_t isTcp; dbus_bool_t isNonceTcp; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); isTcp = strcmp (method, "tcp") == 0; isNonceTcp = strcmp (method, "nonce-tcp") == 0; if (isTcp || isNonceTcp) { const char *host = dbus_address_entry_get_value (entry, "host"); const char *port = dbus_address_entry_get_value (entry, "port"); const char *family = dbus_address_entry_get_value (entry, "family"); const char *noncefile = dbus_address_entry_get_value (entry, "noncefile"); if ((isNonceTcp == TRUE) != (noncefile != NULL)) { _dbus_set_bad_address (error, method, "noncefile", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (port == NULL) { _dbus_set_bad_address (error, method, "port", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } } /** @} */ dbus-1.10.6/dbus/dbus-transport-protected.h0000644000175000017500000001452112602773110020624 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport-protected.h Used by subclasses of DBusTransport object (internal to D-Bus implementation) * * Copyright (C) 2002, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TRANSPORT_PROTECTED_H #define DBUS_TRANSPORT_PROTECTED_H #include #include #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusTransportVTable DBusTransportVTable; /** * The virtual table that must be implemented to * create a new kind of transport. */ struct DBusTransportVTable { void (* finalize) (DBusTransport *transport); /**< The finalize method must free the transport. */ dbus_bool_t (* handle_watch) (DBusTransport *transport, DBusWatch *watch, unsigned int flags); /**< The handle_watch method handles reading/writing * data as indicated by the flags. */ void (* disconnect) (DBusTransport *transport); /**< Disconnect this transport. */ dbus_bool_t (* connection_set) (DBusTransport *transport); /**< Called when transport->connection has been filled in */ void (* do_iteration) (DBusTransport *transport, unsigned int flags, int timeout_milliseconds); /**< Called to do a single "iteration" (block on select/poll * followed by reading or writing data). */ void (* live_messages_changed) (DBusTransport *transport); /**< Outstanding messages counter changed */ dbus_bool_t (* get_socket_fd) (DBusTransport *transport, DBusSocket *fd_p); /**< Get socket file descriptor */ }; /** * Object representing a transport such as a socket. * A transport can shuttle messages from point A to point B, * and is the backend for a #DBusConnection. * */ struct DBusTransport { int refcount; /**< Reference count. */ const DBusTransportVTable *vtable; /**< Virtual methods for this instance. */ DBusConnection *connection; /**< Connection owning this transport. */ DBusMessageLoader *loader; /**< Message-loading buffer. */ DBusAuth *auth; /**< Authentication conversation */ DBusCredentials *credentials; /**< Credentials of other end read from the socket */ long max_live_messages_size; /**< Max total size of received messages. */ long max_live_messages_unix_fds; /**< Max total unix fds of received messages. */ DBusCounter *live_messages; /**< Counter for size/unix fds of all live messages. */ char *address; /**< Address of the server we are connecting to (#NULL for the server side of a transport) */ char *expected_guid; /**< GUID we expect the server to have, #NULL on server side or if we don't have an expectation */ DBusAllowUnixUserFunction unix_user_function; /**< Function for checking whether a user is authorized. */ void *unix_user_data; /**< Data for unix_user_function */ DBusFreeFunction free_unix_user_data; /**< Function to free unix_user_data */ DBusAllowWindowsUserFunction windows_user_function; /**< Function for checking whether a user is authorized. */ void *windows_user_data; /**< Data for windows_user_function */ DBusFreeFunction free_windows_user_data; /**< Function to free windows_user_data */ unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */ unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_peek_is_authenticated() to query value */ unsigned int send_credentials_pending : 1; /**< #TRUE if we need to send credentials */ unsigned int receive_credentials_pending : 1; /**< #TRUE if we need to receive credentials */ unsigned int is_server : 1; /**< #TRUE if on the server side */ unsigned int unused_bytes_recovered : 1; /**< #TRUE if we've recovered unused bytes from auth */ unsigned int allow_anonymous : 1; /**< #TRUE if an anonymous client can connect */ }; dbus_bool_t _dbus_transport_init_base (DBusTransport *transport, const DBusTransportVTable *vtable, const DBusString *server_guid, const DBusString *address); void _dbus_transport_finalize_base (DBusTransport *transport); typedef enum { DBUS_TRANSPORT_OPEN_NOT_HANDLED, /**< we aren't in charge of this address type */ DBUS_TRANSPORT_OPEN_OK, /**< we set up the listen */ DBUS_TRANSPORT_OPEN_BAD_ADDRESS, /**< malformed address */ DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT /**< well-formed address but failed to set it up */ } DBusTransportOpenResult; DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error); #define DBUS_TRANSPORT_CAN_SEND_UNIX_FD(x) \ _dbus_auth_get_unix_fd_negotiated((x)->auth) DBUS_END_DECLS #endif /* DBUS_TRANSPORT_PROTECTED_H */ dbus-1.10.6/dbus/dbus-transport.h0000644000175000017500000002000012602773110016622 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport.h DBusTransport object (internal to D-BUS implementation) * * Copyright (C) 2002, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TRANSPORT_H #define DBUS_TRANSPORT_H #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusTransport DBusTransport; DBusTransport* _dbus_transport_open (DBusAddressEntry *entry, DBusError *error); DBusTransport* _dbus_transport_ref (DBusTransport *transport); void _dbus_transport_unref (DBusTransport *transport); void _dbus_transport_disconnect (DBusTransport *transport); dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport); dbus_bool_t _dbus_transport_peek_is_authenticated (DBusTransport *transport); dbus_bool_t _dbus_transport_try_to_authenticate (DBusTransport *transport); dbus_bool_t _dbus_transport_get_is_anonymous (DBusTransport *transport); dbus_bool_t _dbus_transport_can_pass_unix_fd (DBusTransport *transport); const char* _dbus_transport_get_address (DBusTransport *transport); const char* _dbus_transport_get_server_id (DBusTransport *transport); dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport, DBusWatch *watch, unsigned int condition); dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport, DBusConnection *connection); void _dbus_transport_do_iteration (DBusTransport *transport, unsigned int flags, int timeout_milliseconds); DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport); dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport); void _dbus_transport_set_max_message_size (DBusTransport *transport, long size); long _dbus_transport_get_max_message_size (DBusTransport *transport); void _dbus_transport_set_max_received_size (DBusTransport *transport, long size); long _dbus_transport_get_max_received_size (DBusTransport *transport); void _dbus_transport_set_max_message_unix_fds (DBusTransport *transport, long n); long _dbus_transport_get_max_message_unix_fds (DBusTransport *transport); void _dbus_transport_set_max_received_unix_fds(DBusTransport *transport, long n); long _dbus_transport_get_max_received_unix_fds(DBusTransport *transport); dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport, DBusSocket *fd_p); dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport, unsigned long *uid); dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport, unsigned long *pid); dbus_bool_t _dbus_transport_get_adt_audit_session_data (DBusTransport *transport, void **data, int *data_size); void _dbus_transport_set_unix_user_function (DBusTransport *transport, DBusAllowUnixUserFunction function, void *data, DBusFreeFunction free_data_function, void **old_data, DBusFreeFunction *old_free_data_function); dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport, char **windows_sid_p); dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport, char **label_p); void _dbus_transport_set_windows_user_function (DBusTransport *transport, DBusAllowWindowsUserFunction function, void *data, DBusFreeFunction free_data_function, void **old_data, DBusFreeFunction *old_free_data_function); dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport *transport, const char **mechanisms); void _dbus_transport_set_allow_anonymous (DBusTransport *transport, dbus_bool_t value); int _dbus_transport_get_pending_fds_count (DBusTransport *transport); void _dbus_transport_set_pending_fds_function (DBusTransport *transport, void (* callback) (void *), void *data); /* if DBUS_ENABLE_STATS */ void _dbus_transport_get_stats (DBusTransport *transport, dbus_uint32_t *queue_bytes, dbus_uint32_t *queue_fds, dbus_uint32_t *peak_queue_bytes, dbus_uint32_t *peak_queue_fds); DBUS_END_DECLS #endif /* DBUS_TRANSPORT_H */ dbus-1.10.6/dbus/dbus-transport.c0000644000175000017500000013447012602773110016636 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-transport.c DBusTransport object (internal to D-Bus implementation) * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-transport-protected.h" #include "dbus-transport-unix.h" #include "dbus-transport-socket.h" #include "dbus-connection-internal.h" #include "dbus-watch.h" #include "dbus-auth.h" #include "dbus-address.h" #include "dbus-credentials.h" #include "dbus-mainloop.h" #include "dbus-message.h" #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-server-debug-pipe.h" #endif /** * @defgroup DBusTransport DBusTransport object * @ingroup DBusInternals * @brief "Backend" for a DBusConnection. * * Types and functions related to DBusTransport. A transport is an * abstraction that can send and receive data via various kinds of * network connections or other IPC mechanisms. * * @{ */ /** * @typedef DBusTransport * * Opaque object representing a way message stream. * DBusTransport abstracts various kinds of actual * transport mechanism, such as different network protocols, * or encryption schemes. */ static void live_messages_notify (DBusCounter *counter, void *user_data) { DBusTransport *transport = user_data; _dbus_connection_lock (transport->connection); _dbus_transport_ref (transport); #if 0 _dbus_verbose ("Size counter value is now %d\n", (int) _dbus_counter_get_size_value (counter)); _dbus_verbose ("Unix FD counter value is now %d\n", (int) _dbus_counter_get_unix_fd_value (counter)); #endif /* disable or re-enable the read watch for the transport if * required. */ if (transport->vtable->live_messages_changed) { (* transport->vtable->live_messages_changed) (transport); } _dbus_transport_unref (transport); _dbus_connection_unlock (transport->connection); } /** * Initializes the base class members of DBusTransport. Chained up to * by subclasses in their constructor. The server GUID is the * globally unique ID for the server creating this connection * and will be #NULL for the client side of a connection. The GUID * is in hex format. * * @param transport the transport being created. * @param vtable the subclass vtable. * @param server_guid non-#NULL if this transport is on the server side of a connection * @param address the address of the transport * @returns #TRUE on success. */ dbus_bool_t _dbus_transport_init_base (DBusTransport *transport, const DBusTransportVTable *vtable, const DBusString *server_guid, const DBusString *address) { DBusMessageLoader *loader; DBusAuth *auth; DBusCounter *counter; char *address_copy; DBusCredentials *creds; loader = _dbus_message_loader_new (); if (loader == NULL) return FALSE; if (server_guid) auth = _dbus_auth_server_new (server_guid); else auth = _dbus_auth_client_new (); if (auth == NULL) { _dbus_message_loader_unref (loader); return FALSE; } counter = _dbus_counter_new (); if (counter == NULL) { _dbus_auth_unref (auth); _dbus_message_loader_unref (loader); return FALSE; } creds = _dbus_credentials_new (); if (creds == NULL) { _dbus_counter_unref (counter); _dbus_auth_unref (auth); _dbus_message_loader_unref (loader); return FALSE; } if (server_guid) { _dbus_assert (address == NULL); address_copy = NULL; } else { _dbus_assert (address != NULL); if (!_dbus_string_copy_data (address, &address_copy)) { _dbus_credentials_unref (creds); _dbus_counter_unref (counter); _dbus_auth_unref (auth); _dbus_message_loader_unref (loader); return FALSE; } } transport->refcount = 1; transport->vtable = vtable; transport->loader = loader; transport->auth = auth; transport->live_messages = counter; transport->authenticated = FALSE; transport->disconnected = FALSE; transport->is_server = (server_guid != NULL); transport->send_credentials_pending = !transport->is_server; transport->receive_credentials_pending = transport->is_server; transport->address = address_copy; transport->unix_user_function = NULL; transport->unix_user_data = NULL; transport->free_unix_user_data = NULL; transport->windows_user_function = NULL; transport->windows_user_data = NULL; transport->free_windows_user_data = NULL; transport->expected_guid = NULL; /* Try to default to something that won't totally hose the system, * but doesn't impose too much of a limitation. */ transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live should be more than enough */ transport->max_live_messages_unix_fds = 4096; /* credentials read from socket if any */ transport->credentials = creds; _dbus_counter_set_notify (transport->live_messages, transport->max_live_messages_size, transport->max_live_messages_unix_fds, live_messages_notify, transport); if (transport->address) _dbus_verbose ("Initialized transport on address %s\n", transport->address); return TRUE; } /** * Finalizes base class members of DBusTransport. * Chained up to from subclass finalizers. * * @param transport the transport. */ void _dbus_transport_finalize_base (DBusTransport *transport) { if (!transport->disconnected) _dbus_transport_disconnect (transport); if (transport->free_unix_user_data != NULL) (* transport->free_unix_user_data) (transport->unix_user_data); if (transport->free_windows_user_data != NULL) (* transport->free_windows_user_data) (transport->windows_user_data); _dbus_message_loader_unref (transport->loader); _dbus_auth_unref (transport->auth); _dbus_counter_set_notify (transport->live_messages, 0, 0, NULL, NULL); _dbus_counter_unref (transport->live_messages); dbus_free (transport->address); dbus_free (transport->expected_guid); if (transport->credentials) _dbus_credentials_unref (transport->credentials); } /** * Verifies if a given D-Bus address is a valid address * by attempting to connect to it. If it is, returns the * opened DBusTransport object. If it isn't, returns #NULL * and sets @p error. * * @param address the address to be checked. * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* check_address (const char *address, DBusError *error) { DBusAddressEntry **entries; DBusTransport *transport = NULL; int len, i; _dbus_assert (address != NULL); if (!dbus_parse_address (address, &entries, &len, error)) return NULL; /* not a valid address */ for (i = 0; i < len; i++) { transport = _dbus_transport_open (entries[i], error); if (transport != NULL) break; } dbus_address_entries_free (entries); return transport; } /** * Creates a new transport for the "autostart" method. * This creates a client-side of a transport. * * @param scope scope of autolaunch (Windows only) * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* _dbus_transport_new_for_autolaunch (const char *scope, DBusError *error) { DBusString address; DBusTransport *result = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_get_autolaunch_address (scope, &address, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto out; } result = check_address (_dbus_string_get_const_data (&address), error); if (result == NULL) _DBUS_ASSERT_ERROR_IS_SET (error); else _DBUS_ASSERT_ERROR_IS_CLEAR (error); out: _dbus_string_free (&address); return result; } static DBusTransportOpenResult _dbus_transport_open_autolaunch (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "autolaunch") == 0) { const char *scope = dbus_address_entry_get_value (entry, "scope"); *transport_p = _dbus_transport_new_for_autolaunch (scope, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } } static const struct { DBusTransportOpenResult (* func) (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error); } open_funcs[] = { { _dbus_transport_open_socket }, { _dbus_transport_open_platform_specific }, { _dbus_transport_open_autolaunch } #ifdef DBUS_ENABLE_EMBEDDED_TESTS , { _dbus_transport_open_debug_pipe } #endif }; /** * Try to open a new transport for the given address entry. (This * opens a client-side-of-the-connection transport.) * * @param entry the address entry * @param error location to store reason for failure. * @returns new transport of #NULL on failure. */ DBusTransport* _dbus_transport_open (DBusAddressEntry *entry, DBusError *error) { DBusTransport *transport; const char *expected_guid_orig; char *expected_guid; int i; DBusError tmp_error = DBUS_ERROR_INIT; _DBUS_ASSERT_ERROR_IS_CLEAR (error); transport = NULL; expected_guid_orig = dbus_address_entry_get_value (entry, "guid"); expected_guid = _dbus_strdup (expected_guid_orig); if (expected_guid_orig != NULL && expected_guid == NULL) { _DBUS_SET_OOM (error); return NULL; } for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i) { DBusTransportOpenResult result; _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); result = (* open_funcs[i].func) (entry, &transport, &tmp_error); switch (result) { case DBUS_TRANSPORT_OPEN_OK: _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); goto out; break; case DBUS_TRANSPORT_OPEN_NOT_HANDLED: _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* keep going through the loop of open funcs */ break; case DBUS_TRANSPORT_OPEN_BAD_ADDRESS: _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); goto out; break; case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT: _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); goto out; break; } } out: if (transport == NULL) { if (!dbus_error_is_set (&tmp_error)) _dbus_set_bad_address (&tmp_error, NULL, NULL, "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")"); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); dbus_move_error(&tmp_error, error); dbus_free (expected_guid); } else { _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* In the case of autostart the initial guid is NULL * and the autostart transport recursively calls * _dbus_open_transport wich returns a transport * with a guid. That guid is the definitive one. * * FIXME: if more transports are added they may have * an effect on the expected_guid semantics (i.e. * expected_guid and transport->expected_guid may * both have values). This is very unlikely though * we should either throw asserts here for those * corner cases or refactor the code so it is * clearer on what is expected and what is not */ if(expected_guid) transport->expected_guid = expected_guid; } return transport; } /** * Increments the reference count for the transport. * * @param transport the transport. * @returns the transport. */ DBusTransport * _dbus_transport_ref (DBusTransport *transport) { _dbus_assert (transport->refcount > 0); transport->refcount += 1; return transport; } /** * Decrements the reference count for the transport. * Disconnects and finalizes the transport if * the reference count reaches zero. * * @param transport the transport. */ void _dbus_transport_unref (DBusTransport *transport) { _dbus_assert (transport != NULL); _dbus_assert (transport->refcount > 0); transport->refcount -= 1; if (transport->refcount == 0) { _dbus_verbose ("finalizing\n"); _dbus_assert (transport->vtable->finalize != NULL); (* transport->vtable->finalize) (transport); } } /** * Closes our end of the connection to a remote application. Further * attempts to use this transport will fail. Only the first call to * _dbus_transport_disconnect() will have an effect. * * @param transport the transport. * */ void _dbus_transport_disconnect (DBusTransport *transport) { _dbus_verbose ("start\n"); _dbus_assert (transport->vtable->disconnect != NULL); if (transport->disconnected) return; (* transport->vtable->disconnect) (transport); transport->disconnected = TRUE; _dbus_verbose ("end\n"); } /** * Returns #TRUE if the transport has not been disconnected. * Disconnection can result from _dbus_transport_disconnect() * or because the server drops its end of the connection. * * @param transport the transport. * @returns whether we're connected */ dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport) { return !transport->disconnected; } static dbus_bool_t auth_via_unix_user_function (DBusTransport *transport) { DBusCredentials *auth_identity; dbus_bool_t allow; DBusConnection *connection; DBusAllowUnixUserFunction unix_user_function; void *unix_user_data; dbus_uid_t uid; /* Dropping the lock here probably isn't that safe. */ auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); connection = transport->connection; unix_user_function = transport->unix_user_function; unix_user_data = transport->unix_user_data; uid = _dbus_credentials_get_unix_uid (auth_identity); _dbus_verbose ("unlock\n"); _dbus_connection_unlock (connection); allow = (* unix_user_function) (connection, uid, unix_user_data); _dbus_verbose ("lock post unix user function\n"); _dbus_connection_lock (connection); if (allow) { _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid); } else { _dbus_verbose ("Client UID "DBUS_UID_FORMAT " was rejected, disconnecting\n", _dbus_credentials_get_unix_uid (auth_identity)); _dbus_transport_disconnect (transport); } return allow; } static dbus_bool_t auth_via_windows_user_function (DBusTransport *transport) { DBusCredentials *auth_identity; dbus_bool_t allow; DBusConnection *connection; DBusAllowWindowsUserFunction windows_user_function; void *windows_user_data; char *windows_sid; /* Dropping the lock here probably isn't that safe. */ auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); connection = transport->connection; windows_user_function = transport->windows_user_function; windows_user_data = transport->unix_user_data; windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); if (windows_sid == NULL) { /* OOM */ return FALSE; } _dbus_verbose ("unlock\n"); _dbus_connection_unlock (connection); allow = (* windows_user_function) (connection, windows_sid, windows_user_data); _dbus_verbose ("lock post windows user function\n"); _dbus_connection_lock (connection); if (allow) { _dbus_verbose ("Client SID '%s' authorized\n", windows_sid); } else { _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n", _dbus_credentials_get_windows_sid (auth_identity)); _dbus_transport_disconnect (transport); } return allow; } static dbus_bool_t auth_via_default_rules (DBusTransport *transport) { DBusCredentials *auth_identity; DBusCredentials *our_identity; dbus_bool_t allow; auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); /* By default, connection is allowed if the client is 1) root or 2) * has the same UID as us or 3) anonymous is allowed. */ our_identity = _dbus_credentials_new_from_current_process (); if (our_identity == NULL) { /* OOM */ return FALSE; } if (transport->allow_anonymous || _dbus_credentials_get_unix_uid (auth_identity) == 0 || _dbus_credentials_same_user (our_identity, auth_identity)) { if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID)) _dbus_verbose ("Client authorized as SID '%s'" "matching our SID '%s'\n", _dbus_credentials_get_windows_sid(auth_identity), _dbus_credentials_get_windows_sid(our_identity)); else _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT " matching our UID "DBUS_UID_FORMAT"\n", _dbus_credentials_get_unix_uid(auth_identity), _dbus_credentials_get_unix_uid(our_identity)); /* We have authenticated! */ allow = TRUE; } else { if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID)) _dbus_verbose ("Client authorized as SID '%s'" " but our SID is '%s', disconnecting\n", (_dbus_credentials_get_windows_sid(auth_identity) ? _dbus_credentials_get_windows_sid(auth_identity) : ""), (_dbus_credentials_get_windows_sid(our_identity) ? _dbus_credentials_get_windows_sid(our_identity) : "")); else _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT " but our UID is "DBUS_UID_FORMAT", disconnecting\n", _dbus_credentials_get_unix_uid(auth_identity), _dbus_credentials_get_unix_uid(our_identity)); _dbus_transport_disconnect (transport); allow = FALSE; } _dbus_credentials_unref (our_identity); return allow; } /** * Returns #TRUE if we have been authenticated. It will return #TRUE even if * the transport is now disconnected, but was ever authenticated before * disconnecting. * * This replaces the older _dbus_transport_get_is_authenticated() which * had side-effects. * * @param transport the transport * @returns whether we're authenticated */ dbus_bool_t _dbus_transport_peek_is_authenticated (DBusTransport *transport) { return transport->authenticated; } /** * Returns #TRUE if we have been authenticated. It will return #TRUE even if * the transport is now disconnected, but was ever authenticated before * disconnecting. * * If we have not finished authenticating, but we have enough buffered input * to finish the job, then this function will do so before it returns. * * This used to be called _dbus_transport_get_is_authenticated(), but that * name seems inappropriate for a function with side-effects. * * @todo we drop connection->mutex when calling the unix_user_function, * and windows_user_function, which may not be safe really. * * @param transport the transport * @returns whether we're authenticated */ dbus_bool_t _dbus_transport_try_to_authenticate (DBusTransport *transport) { if (transport->authenticated) return TRUE; else { dbus_bool_t maybe_authenticated; if (transport->disconnected) return FALSE; /* paranoia ref since we call user callbacks sometimes */ _dbus_connection_ref_unlocked (transport->connection); maybe_authenticated = (!(transport->send_credentials_pending || transport->receive_credentials_pending)); if (maybe_authenticated) { switch (_dbus_auth_do_work (transport->auth)) { case DBUS_AUTH_STATE_AUTHENTICATED: /* leave as maybe_authenticated */ break; default: maybe_authenticated = FALSE; } } /* If we're the client, verify the GUID */ if (maybe_authenticated && !transport->is_server) { const char *server_guid; server_guid = _dbus_auth_get_guid_from_server (transport->auth); _dbus_assert (server_guid != NULL); if (transport->expected_guid && strcmp (transport->expected_guid, server_guid) != 0) { _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n", transport->expected_guid, server_guid); _dbus_transport_disconnect (transport); _dbus_connection_unref_unlocked (transport->connection); return FALSE; } } /* If we're the server, see if we want to allow this identity to proceed. */ if (maybe_authenticated && transport->is_server) { dbus_bool_t allow; DBusCredentials *auth_identity; auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); /* If we have an auth'd user and a user function, delegate * deciding whether auth credentials are good enough to the * app; otherwise, use our default decision process. */ if (transport->unix_user_function != NULL && _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID)) { allow = auth_via_unix_user_function (transport); } else if (transport->windows_user_function != NULL && _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID)) { allow = auth_via_windows_user_function (transport); } else { allow = auth_via_default_rules (transport); } if (!allow) maybe_authenticated = FALSE; } transport->authenticated = maybe_authenticated; _dbus_connection_unref_unlocked (transport->connection); return maybe_authenticated; } } /** * See dbus_connection_get_is_anonymous(). * * @param transport the transport * @returns #TRUE if not authenticated or authenticated as anonymous */ dbus_bool_t _dbus_transport_get_is_anonymous (DBusTransport *transport) { DBusCredentials *auth_identity; if (!transport->authenticated) return TRUE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_are_anonymous (auth_identity)) return TRUE; else return FALSE; } /** * Returns TRUE if the transport supports sending unix fds. * * @param transport the transport * @returns #TRUE if TRUE it is possible to send unix fds across the transport. */ dbus_bool_t _dbus_transport_can_pass_unix_fd(DBusTransport *transport) { return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport); } /** * Gets the address of a transport. It will be * #NULL for a server-side transport. * * @param transport the transport * @returns transport's address */ const char* _dbus_transport_get_address (DBusTransport *transport) { return transport->address; } /** * Gets the id of the server we are connected to (see * dbus_server_get_id()). Only works on client side. * * @param transport the transport * @returns transport's server's id or #NULL if we are the server side */ const char* _dbus_transport_get_server_id (DBusTransport *transport) { if (transport->is_server) return NULL; else if (transport->authenticated) return _dbus_auth_get_guid_from_server (transport->auth); else return transport->expected_guid; } /** * Handles a watch by reading data, writing data, or disconnecting * the transport, as appropriate for the given condition. * * @param transport the transport. * @param watch the watch. * @param condition the current state of the watched file descriptor. * @returns #FALSE if not enough memory to fully handle the watch */ dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport, DBusWatch *watch, unsigned int condition) { dbus_bool_t retval; _dbus_assert (transport->vtable->handle_watch != NULL); if (transport->disconnected) return TRUE; if (dbus_watch_get_socket (watch) < 0) { _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n"); return TRUE; } _dbus_watch_sanitize_condition (watch, &condition); _dbus_transport_ref (transport); _dbus_watch_ref (watch); retval = (* transport->vtable->handle_watch) (transport, watch, condition); _dbus_watch_unref (watch); _dbus_transport_unref (transport); return retval; } /** * Sets the connection using this transport. Allows the transport * to add watches to the connection, queue incoming messages, * and pull outgoing messages. * * @param transport the transport. * @param connection the connection. * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport, DBusConnection *connection) { _dbus_assert (transport->vtable->connection_set != NULL); _dbus_assert (transport->connection == NULL); transport->connection = connection; _dbus_transport_ref (transport); if (!(* transport->vtable->connection_set) (transport)) transport->connection = NULL; _dbus_transport_unref (transport); return transport->connection != NULL; } /** * Get the socket file descriptor, if any. * * @param transport the transport * @param fd_p pointer to fill in with the descriptor * @returns #TRUE if a descriptor was available */ dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport, DBusSocket *fd_p) { dbus_bool_t retval; if (transport->vtable->get_socket_fd == NULL) return FALSE; if (transport->disconnected) return FALSE; _dbus_transport_ref (transport); retval = (* transport->vtable->get_socket_fd) (transport, fd_p); _dbus_transport_unref (transport); return retval; } /** * Performs a single poll()/select() on the transport's file * descriptors and then reads/writes data as appropriate, * queueing incoming messages and sending outgoing messages. * This is the backend for _dbus_connection_do_iteration(). * See _dbus_connection_do_iteration() for full details. * * @param transport the transport. * @param flags indicates whether to read or write, and whether to block. * @param timeout_milliseconds if blocking, timeout or -1 for no timeout. */ void _dbus_transport_do_iteration (DBusTransport *transport, unsigned int flags, int timeout_milliseconds) { _dbus_assert (transport->vtable->do_iteration != NULL); _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n", flags, timeout_milliseconds, !transport->disconnected); if ((flags & (DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_DO_READING)) == 0) return; /* Nothing to do */ if (transport->disconnected) return; _dbus_transport_ref (transport); (* transport->vtable->do_iteration) (transport, flags, timeout_milliseconds); _dbus_transport_unref (transport); _dbus_verbose ("end\n"); } static dbus_bool_t recover_unused_bytes (DBusTransport *transport) { if (_dbus_auth_needs_decoding (transport->auth)) { DBusString plaintext; const DBusString *encoded; DBusString *buffer; int orig_len; if (!_dbus_string_init (&plaintext)) goto nomem; _dbus_auth_get_unused_bytes (transport->auth, &encoded); if (!_dbus_auth_decode_data (transport->auth, encoded, &plaintext)) { _dbus_string_free (&plaintext); goto nomem; } _dbus_message_loader_get_buffer (transport->loader, &buffer); orig_len = _dbus_string_get_length (buffer); if (!_dbus_string_move (&plaintext, 0, buffer, orig_len)) { _dbus_string_free (&plaintext); goto nomem; } _dbus_verbose (" %d unused bytes sent to message loader\n", _dbus_string_get_length (buffer) - orig_len); _dbus_message_loader_return_buffer (transport->loader, buffer); _dbus_auth_delete_unused_bytes (transport->auth); _dbus_string_free (&plaintext); } else { const DBusString *bytes; DBusString *buffer; int orig_len; dbus_bool_t succeeded; _dbus_message_loader_get_buffer (transport->loader, &buffer); orig_len = _dbus_string_get_length (buffer); _dbus_auth_get_unused_bytes (transport->auth, &bytes); succeeded = TRUE; if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer))) succeeded = FALSE; _dbus_verbose (" %d unused bytes sent to message loader\n", _dbus_string_get_length (buffer) - orig_len); _dbus_message_loader_return_buffer (transport->loader, buffer); if (succeeded) _dbus_auth_delete_unused_bytes (transport->auth); else goto nomem; } return TRUE; nomem: _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n"); return FALSE; } /** * Reports our current dispatch status (whether there's buffered * data to be queued as messages, or not, or we need memory). * * @param transport the transport * @returns current status */ DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport) { if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size || _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds) return DBUS_DISPATCH_COMPLETE; /* complete for now */ if (!_dbus_transport_try_to_authenticate (transport)) { if (_dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) return DBUS_DISPATCH_NEED_MEMORY; else if (!_dbus_transport_try_to_authenticate (transport)) return DBUS_DISPATCH_COMPLETE; } if (!transport->unused_bytes_recovered && !recover_unused_bytes (transport)) return DBUS_DISPATCH_NEED_MEMORY; transport->unused_bytes_recovered = TRUE; if (!_dbus_message_loader_queue_messages (transport->loader)) return DBUS_DISPATCH_NEED_MEMORY; if (_dbus_message_loader_peek_message (transport->loader) != NULL) return DBUS_DISPATCH_DATA_REMAINS; else return DBUS_DISPATCH_COMPLETE; } /** * Processes data we've read while handling a watch, potentially * converting some of it to messages and queueing those messages on * the connection. * * @param transport the transport * @returns #TRUE if we had enough memory to queue all messages */ dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport) { DBusDispatchStatus status; #if 0 _dbus_verbose ("_dbus_transport_queue_messages()\n"); #endif /* Queue any messages */ while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS) { DBusMessage *message; DBusList *link; link = _dbus_message_loader_pop_message_link (transport->loader); _dbus_assert (link != NULL); message = link->data; _dbus_verbose ("queueing received message %p\n", message); if (!_dbus_message_add_counter (message, transport->live_messages)) { _dbus_message_loader_putback_message_link (transport->loader, link); status = DBUS_DISPATCH_NEED_MEMORY; break; } else { /* We didn't call the notify function when we added the counter, so * catch up now. Since we have the connection's lock, it's desirable * that we bypass the notify function and call this virtual method * directly. */ if (transport->vtable->live_messages_changed) (* transport->vtable->live_messages_changed) (transport); /* pass ownership of link and message ref to connection */ _dbus_connection_queue_received_message_link (transport->connection, link); } } if (_dbus_message_loader_get_is_corrupted (transport->loader)) { _dbus_verbose ("Corrupted message stream, disconnecting\n"); _dbus_transport_disconnect (transport); } return status != DBUS_DISPATCH_NEED_MEMORY; } /** * See dbus_connection_set_max_message_size(). * * @param transport the transport * @param size the max size of a single message */ void _dbus_transport_set_max_message_size (DBusTransport *transport, long size) { _dbus_message_loader_set_max_message_size (transport->loader, size); } /** * See dbus_connection_set_max_message_unix_fds(). * * @param transport the transport * @param n the max number of unix fds of a single message */ void _dbus_transport_set_max_message_unix_fds (DBusTransport *transport, long n) { _dbus_message_loader_set_max_message_unix_fds (transport->loader, n); } /** * See dbus_connection_get_max_message_size(). * * @param transport the transport * @returns max message size */ long _dbus_transport_get_max_message_size (DBusTransport *transport) { return _dbus_message_loader_get_max_message_size (transport->loader); } /** * See dbus_connection_get_max_message_unix_fds(). * * @param transport the transport * @returns max message unix fds */ long _dbus_transport_get_max_message_unix_fds (DBusTransport *transport) { return _dbus_message_loader_get_max_message_unix_fds (transport->loader); } /** * See dbus_connection_set_max_received_size(). * * @param transport the transport * @param size the max size of all incoming messages */ void _dbus_transport_set_max_received_size (DBusTransport *transport, long size) { transport->max_live_messages_size = size; _dbus_counter_set_notify (transport->live_messages, transport->max_live_messages_size, transport->max_live_messages_unix_fds, live_messages_notify, transport); } /** * See dbus_connection_set_max_received_unix_fds(). * * @param transport the transport * @param n the max unix fds of all incoming messages */ void _dbus_transport_set_max_received_unix_fds (DBusTransport *transport, long n) { transport->max_live_messages_unix_fds = n; _dbus_counter_set_notify (transport->live_messages, transport->max_live_messages_size, transport->max_live_messages_unix_fds, live_messages_notify, transport); } /** * See dbus_connection_get_max_received_size(). * * @param transport the transport * @returns max bytes for all live messages */ long _dbus_transport_get_max_received_size (DBusTransport *transport) { return transport->max_live_messages_size; } /** * See dbus_connection_set_max_received_unix_fds(). * * @param transport the transport * @returns max unix fds for all live messages */ long _dbus_transport_get_max_received_unix_fds (DBusTransport *transport) { return transport->max_live_messages_unix_fds; } /** * See dbus_connection_get_unix_user(). * * @param transport the transport * @param uid return location for the user ID * @returns #TRUE if uid is filled in with a valid user ID */ dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport, unsigned long *uid) { DBusCredentials *auth_identity; *uid = _DBUS_INT32_MAX; /* better than some root or system user in * case of bugs in the caller. Caller should * never use this value on purpose, however. */ if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID)) { *uid = _dbus_credentials_get_unix_uid (auth_identity); return TRUE; } else return FALSE; } /** * See dbus_connection_get_unix_process_id(). * * @param transport the transport * @param pid return location for the process ID * @returns #TRUE if uid is filled in with a valid process ID */ dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport, unsigned long *pid) { DBusCredentials *auth_identity; *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose, * but we set it to a safe number, INT_MAX, * just to root out possible bugs in bad callers. */ if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_PROCESS_ID)) { *pid = _dbus_credentials_get_pid (auth_identity); return TRUE; } else return FALSE; } /** * See dbus_connection_get_adt_audit_session_data(). * * @param transport the transport * @param data return location for the ADT audit data * @param data_size return length of audit data * @returns #TRUE if audit data is filled in with a valid ucred */ dbus_bool_t _dbus_transport_get_adt_audit_session_data (DBusTransport *transport, void **data, int *data_size) { DBusCredentials *auth_identity; *data = NULL; *data_size = 0; if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID)) { *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity); *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity); return TRUE; } else return FALSE; } /** * See dbus_connection_set_unix_user_function(). * * @param transport the transport * @param function the predicate * @param data data to pass to the predicate * @param free_data_function function to free the data * @param old_data the old user data to be freed * @param old_free_data_function old free data function to free it with */ void _dbus_transport_set_unix_user_function (DBusTransport *transport, DBusAllowUnixUserFunction function, void *data, DBusFreeFunction free_data_function, void **old_data, DBusFreeFunction *old_free_data_function) { *old_data = transport->unix_user_data; *old_free_data_function = transport->free_unix_user_data; transport->unix_user_function = function; transport->unix_user_data = data; transport->free_unix_user_data = free_data_function; } dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport, char **label_p) { DBusCredentials *auth_identity; *label_p = NULL; if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_LINUX_SECURITY_LABEL)) { /* If no memory, we are supposed to return TRUE and set NULL */ *label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity)); return TRUE; } else { return FALSE; } } /** * See dbus_connection_get_windows_user(). * * @param transport the transport * @param windows_sid_p return location for the user ID * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it */ dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport, char **windows_sid_p) { DBusCredentials *auth_identity; *windows_sid_p = NULL; if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID)) { /* If no memory, we are supposed to return TRUE and set NULL */ *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); return TRUE; } else return FALSE; } /** * See dbus_connection_set_windows_user_function(). * * @param transport the transport * @param function the predicate * @param data data to pass to the predicate * @param free_data_function function to free the data * @param old_data the old user data to be freed * @param old_free_data_function old free data function to free it with */ void _dbus_transport_set_windows_user_function (DBusTransport *transport, DBusAllowWindowsUserFunction function, void *data, DBusFreeFunction free_data_function, void **old_data, DBusFreeFunction *old_free_data_function) { *old_data = transport->windows_user_data; *old_free_data_function = transport->free_windows_user_data; transport->windows_user_function = function; transport->windows_user_data = data; transport->free_windows_user_data = free_data_function; } /** * Sets the SASL authentication mechanisms supported by this transport. * * @param transport the transport * @param mechanisms the #NULL-terminated array of mechanisms * * @returns #FALSE if no memory */ dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport *transport, const char **mechanisms) { return _dbus_auth_set_mechanisms (transport->auth, mechanisms); } /** * See dbus_connection_set_allow_anonymous() * * @param transport the transport * @param value #TRUE to allow anonymous connection */ void _dbus_transport_set_allow_anonymous (DBusTransport *transport, dbus_bool_t value) { transport->allow_anonymous = value != FALSE; } /** * Return how many file descriptors are pending in the loader * * @param transport the transport */ int _dbus_transport_get_pending_fds_count (DBusTransport *transport) { return _dbus_message_loader_get_pending_fds_count (transport->loader); } /** * Register a function to be called whenever the number of pending file * descriptors in the loader change. * * @param transport the transport * @param callback the callback */ void _dbus_transport_set_pending_fds_function (DBusTransport *transport, void (* callback) (void *), void *data) { _dbus_message_loader_set_pending_fds_function (transport->loader, callback, data); } #ifdef DBUS_ENABLE_STATS void _dbus_transport_get_stats (DBusTransport *transport, dbus_uint32_t *queue_bytes, dbus_uint32_t *queue_fds, dbus_uint32_t *peak_queue_bytes, dbus_uint32_t *peak_queue_fds) { if (queue_bytes != NULL) *queue_bytes = _dbus_counter_get_size_value (transport->live_messages); if (queue_fds != NULL) *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages); if (peak_queue_bytes != NULL) *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages); if (peak_queue_fds != NULL) *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages); } #endif /* DBUS_ENABLE_STATS */ /** @} */ dbus-1.10.6/dbus/dbus-threads.c0000644000175000017500000002527312602773110016234 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-threads.h D-Bus threads handling * * Copyright (C) 2002, 2003, 2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-threads.h" #include "dbus-internals.h" #include "dbus-threads-internal.h" #include "dbus-list.h" static int thread_init_generation = 0; /** * @defgroup DBusThreadsInternals Thread functions * @ingroup DBusInternals * @brief _dbus_rmutex_lock(), etc. * * Functions and macros related to threads and thread locks. * * @{ */ /** * Creates a new mutex * or creates a no-op mutex if threads are not initialized. * May return #NULL even if threads are initialized, indicating * out-of-memory. * * If possible, the mutex returned by this function is recursive, to * avoid deadlocks. However, that cannot be relied on. * * @param location_p the location of the new mutex, can return #NULL on OOM */ void _dbus_rmutex_new_at_location (DBusRMutex **location_p) { _dbus_assert (location_p != NULL); if (!dbus_threads_init_default ()) { *location_p = NULL; return; } *location_p = _dbus_platform_rmutex_new (); } /** * Creates a new mutex * or creates a no-op mutex if threads are not initialized. * May return #NULL even if threads are initialized, indicating * out-of-memory. * * The returned mutex is suitable for use with condition variables. * * @param location_p the location of the new mutex, can return #NULL on OOM */ void _dbus_cmutex_new_at_location (DBusCMutex **location_p) { _dbus_assert (location_p != NULL); if (!dbus_threads_init_default ()) { *location_p = NULL; return; } *location_p = _dbus_platform_cmutex_new (); } /** * Frees a DBusRMutex; does nothing if passed a #NULL pointer. */ void _dbus_rmutex_free_at_location (DBusRMutex **location_p) { if (location_p == NULL) return; if (*location_p != NULL) _dbus_platform_rmutex_free (*location_p); } /** * Frees a DBusCMutex; does nothing if passed a #NULL pointer. */ void _dbus_cmutex_free_at_location (DBusCMutex **location_p) { if (location_p == NULL) return; if (*location_p != NULL) _dbus_platform_cmutex_free (*location_p); } /** * Locks a mutex. Does nothing if passed a #NULL pointer. * Locks may be recursive if threading implementation initialized * recursive locks. */ void _dbus_rmutex_lock (DBusRMutex *mutex) { if (mutex == NULL) return; _dbus_platform_rmutex_lock (mutex); } /** * Locks a mutex. Does nothing if passed a #NULL pointer. * Locks may be recursive if threading implementation initialized * recursive locks. */ void _dbus_cmutex_lock (DBusCMutex *mutex) { if (mutex == NULL) return; _dbus_platform_cmutex_lock (mutex); } /** * Unlocks a mutex. Does nothing if passed a #NULL pointer. * * @returns #TRUE on success */ void _dbus_rmutex_unlock (DBusRMutex *mutex) { if (mutex == NULL) return; _dbus_platform_rmutex_unlock (mutex); } /** * Unlocks a mutex. Does nothing if passed a #NULL pointer. * * @returns #TRUE on success */ void _dbus_cmutex_unlock (DBusCMutex *mutex) { if (mutex == NULL) return; _dbus_platform_cmutex_unlock (mutex); } /** * Creates a new condition variable using the function supplied * to dbus_threads_init(), or creates a no-op condition variable * if threads are not initialized. May return #NULL even if * threads are initialized, indicating out-of-memory. * * @returns new mutex or #NULL */ DBusCondVar * _dbus_condvar_new (void) { if (!dbus_threads_init_default ()) return NULL; return _dbus_platform_condvar_new (); } /** * This does the same thing as _dbus_condvar_new. It however * gives another level of indirection by allocating a pointer * to point to the condvar location; this used to be useful. * * @returns the location of a new condvar or #NULL on OOM */ void _dbus_condvar_new_at_location (DBusCondVar **location_p) { _dbus_assert (location_p != NULL); *location_p = _dbus_condvar_new(); } /** * Frees a conditional variable created with dbus_condvar_new(); does * nothing if passed a #NULL pointer. */ void _dbus_condvar_free (DBusCondVar *cond) { if (cond == NULL) return; _dbus_platform_condvar_free (cond); } /** * Frees a condition variable; does nothing if passed a #NULL pointer. */ void _dbus_condvar_free_at_location (DBusCondVar **location_p) { if (location_p == NULL) return; if (*location_p != NULL) _dbus_platform_condvar_free (*location_p); } /** * Atomically unlocks the mutex and waits for the conditions * variable to be signalled. Locks the mutex again before * returning. * Does nothing if passed a #NULL pointer. */ void _dbus_condvar_wait (DBusCondVar *cond, DBusCMutex *mutex) { if (cond == NULL || mutex == NULL) return; _dbus_platform_condvar_wait (cond, mutex); } /** * Atomically unlocks the mutex and waits for the conditions variable * to be signalled, or for a timeout. Locks the mutex again before * returning. Does nothing if passed a #NULL pointer. Return value * is #FALSE if we timed out, #TRUE otherwise. * * @param cond the condition variable * @param mutex the mutex * @param timeout_milliseconds the maximum time to wait * @returns #FALSE if the timeout occurred, #TRUE if not */ dbus_bool_t _dbus_condvar_wait_timeout (DBusCondVar *cond, DBusCMutex *mutex, int timeout_milliseconds) { if (cond == NULL || mutex == NULL) return TRUE; return _dbus_platform_condvar_wait_timeout (cond, mutex, timeout_milliseconds); } /** * If there are threads waiting on the condition variable, wake * up exactly one. * Does nothing if passed a #NULL pointer. */ void _dbus_condvar_wake_one (DBusCondVar *cond) { if (cond == NULL) return; _dbus_platform_condvar_wake_one (cond); } static DBusRMutex *global_locks[_DBUS_N_GLOBAL_LOCKS] = { NULL }; static void shutdown_global_locks (void *nil) { int i; for (i = 0; i < _DBUS_N_GLOBAL_LOCKS; i++) { _dbus_assert (global_locks[i] != NULL); _dbus_platform_rmutex_free (global_locks[i]); global_locks[i] = NULL; } } static dbus_bool_t init_global_locks (void) { int i; dbus_bool_t ok; for (i = 0; i < _DBUS_N_GLOBAL_LOCKS; i++) { _dbus_assert (global_locks[i] == NULL); global_locks[i] = _dbus_platform_rmutex_new (); if (global_locks[i] == NULL) goto failed; } _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]); ok = _dbus_register_shutdown_func_unlocked (shutdown_global_locks, NULL); _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]); if (!ok) goto failed; return TRUE; failed: for (i = i - 1; i >= 0; i--) { _dbus_platform_rmutex_free (global_locks[i]); global_locks[i] = NULL; } return FALSE; } dbus_bool_t _dbus_lock (DBusGlobalLock lock) { _dbus_assert (lock >= 0); _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS); if (thread_init_generation != _dbus_current_generation && !dbus_threads_init_default ()) return FALSE; _dbus_platform_rmutex_lock (global_locks[lock]); return TRUE; } void _dbus_unlock (DBusGlobalLock lock) { _dbus_assert (lock >= 0); _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS); _dbus_platform_rmutex_unlock (global_locks[lock]); } /** @} */ /* end of internals */ /** * @defgroup DBusThreads Thread functions * @ingroup DBus * @brief dbus_threads_init() and dbus_threads_init_default() * * Functions and macros related to threads and thread locks. * * If threads are initialized, the D-Bus library has locks on all * global data structures. In addition, each #DBusConnection has a * lock, so only one thread at a time can touch the connection. (See * @ref DBusConnection for more on connection locking.) * * Most other objects, however, do not have locks - they can only be * used from a single thread at a time, unless you lock them yourself. * For example, a #DBusMessage can't be modified from two threads * at once. * * @{ */ /** * Initializes threads, like dbus_threads_init_default(). * This version previously allowed user-specified threading * primitives, but since D-Bus 1.6 it ignores them and behaves * exactly like dbus_threads_init_default(). * * @param functions ignored, formerly functions for using threads * @returns #TRUE on success, #FALSE if no memory */ dbus_bool_t dbus_threads_init (const DBusThreadFunctions *functions) { _dbus_threads_lock_platform_specific (); if (thread_init_generation == _dbus_current_generation) { _dbus_threads_unlock_platform_specific (); return TRUE; } if (!_dbus_threads_init_platform_specific() || !init_global_locks ()) { _dbus_threads_unlock_platform_specific (); return FALSE; } thread_init_generation = _dbus_current_generation; _dbus_threads_unlock_platform_specific (); return TRUE; } /* Default thread implemenation */ /** * Initializes threads. If this function is not called, the D-Bus * library will not lock any data structures. If it is called, D-Bus * will do locking, at some cost in efficiency. * * Since D-Bus 1.7 it is safe to call this function from any thread, * any number of times (but it must be called before any other * libdbus API is used). * * In D-Bus 1.6 or older, this function must be called in the main thread * before any other thread starts. As a result, it is not sufficient to * call this function in a library or plugin, unless the library or plugin * imposes a similar requirement on its callers. * * dbus_shutdown() reverses the effects of this function when it * resets all global state in libdbus. * * @returns #TRUE on success, #FALSE if not enough memory */ dbus_bool_t dbus_threads_init_default (void) { return dbus_threads_init (NULL); } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS dbus_bool_t _dbus_threads_init_debug (void) { return dbus_threads_init (NULL); } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-threads-internal.h0000644000175000017500000000777712602773110020064 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-threads-internal.h D-Bus thread primitives * * Copyright (C) 2002, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_THREADS_INTERNAL_H #define DBUS_THREADS_INTERNAL_H #include #include #include /** * @addtogroup DBusThreadsInternals * @{ */ /** * A mutex which is recursive if possible, else non-recursive. * This is typically recursive, but that cannot be relied upon. */ typedef struct DBusRMutex DBusRMutex; /** * A mutex suitable for use with condition variables. * This is typically non-recursive. */ typedef struct DBusCMutex DBusCMutex; /** @} */ DBUS_BEGIN_DECLS DBUS_PRIVATE_EXPORT void _dbus_rmutex_lock (DBusRMutex *mutex); DBUS_PRIVATE_EXPORT void _dbus_rmutex_unlock (DBusRMutex *mutex); void _dbus_rmutex_new_at_location (DBusRMutex **location_p); void _dbus_rmutex_free_at_location (DBusRMutex **location_p); void _dbus_cmutex_lock (DBusCMutex *mutex); void _dbus_cmutex_unlock (DBusCMutex *mutex); void _dbus_cmutex_new_at_location (DBusCMutex **location_p); void _dbus_cmutex_free_at_location (DBusCMutex **location_p); DBusCondVar* _dbus_condvar_new (void); void _dbus_condvar_free (DBusCondVar *cond); void _dbus_condvar_wait (DBusCondVar *cond, DBusCMutex *mutex); dbus_bool_t _dbus_condvar_wait_timeout (DBusCondVar *cond, DBusCMutex *mutex, int timeout_milliseconds); void _dbus_condvar_wake_one (DBusCondVar *cond); void _dbus_condvar_new_at_location (DBusCondVar **location_p); void _dbus_condvar_free_at_location (DBusCondVar **location_p); /* Private to threading implementations and dbus-threads.c */ DBusRMutex *_dbus_platform_rmutex_new (void); void _dbus_platform_rmutex_free (DBusRMutex *mutex); void _dbus_platform_rmutex_lock (DBusRMutex *mutex); void _dbus_platform_rmutex_unlock (DBusRMutex *mutex); DBusCMutex *_dbus_platform_cmutex_new (void); void _dbus_platform_cmutex_free (DBusCMutex *mutex); void _dbus_platform_cmutex_lock (DBusCMutex *mutex); void _dbus_platform_cmutex_unlock (DBusCMutex *mutex); DBusCondVar* _dbus_platform_condvar_new (void); void _dbus_platform_condvar_free (DBusCondVar *cond); void _dbus_platform_condvar_wait (DBusCondVar *cond, DBusCMutex *mutex); dbus_bool_t _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, DBusCMutex *mutex, int timeout_milliseconds); void _dbus_platform_condvar_wake_one (DBusCondVar *cond); DBUS_END_DECLS #endif /* DBUS_THREADS_INTERNAL_H */ dbus-1.10.6/dbus/dbus-timeout.h0000644000175000017500000000634712602773110016276 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-timeout.h DBusTimeout internal interfaces * * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_TIMEOUT_H #define DBUS_TIMEOUT_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusTimeoutInternals * @{ */ /* Public methods on DBusTimeout are in dbus-connection.h */ typedef struct DBusTimeoutList DBusTimeoutList; /** function to run when the timeout is handled */ typedef dbus_bool_t (* DBusTimeoutHandler) (void *data); DBUS_PRIVATE_EXPORT DBusTimeout* _dbus_timeout_new (int interval, DBusTimeoutHandler handler, void *data, DBusFreeFunction free_data_function); DBusTimeout* _dbus_timeout_ref (DBusTimeout *timeout); DBUS_PRIVATE_EXPORT void _dbus_timeout_unref (DBusTimeout *timeout); DBUS_PRIVATE_EXPORT void _dbus_timeout_set_interval (DBusTimeout *timeout, int interval); DBUS_PRIVATE_EXPORT void _dbus_timeout_set_enabled (DBusTimeout *timeout, dbus_bool_t enabled); DBusTimeoutList *_dbus_timeout_list_new (void); void _dbus_timeout_list_free (DBusTimeoutList *timeout_list); dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); dbus_bool_t _dbus_timeout_list_add_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout); void _dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout); void _dbus_timeout_list_toggle_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout, dbus_bool_t enabled); /** @} */ DBUS_END_DECLS #endif /* DBUS_TIMEOUT_H */ dbus-1.10.6/dbus/dbus-timeout.c0000644000175000017500000003356712602773110016275 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-timeout.c DBusTimeout implementation * * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-timeout.h" #include "dbus-list.h" /** * @defgroup DBusTimeoutInternals DBusTimeout implementation details * @ingroup DBusInternals * @brief implementation details for DBusTimeout * * @{ */ /** * Internals of DBusTimeout */ struct DBusTimeout { int refcount; /**< Reference count */ int interval; /**< Timeout interval in milliseconds. */ DBusTimeoutHandler handler; /**< Timeout handler. */ void *handler_data; /**< Timeout handler data. */ DBusFreeFunction free_handler_data_function; /**< Free the timeout handler data. */ void *data; /**< Application data. */ DBusFreeFunction free_data_function; /**< Free the application data. */ unsigned int enabled : 1; /**< True if timeout is active. */ }; /** * Creates a new DBusTimeout, enabled by default. * @param interval the timeout interval in milliseconds. * @param handler function to call when the timeout occurs. * @param data data to pass to the handler * @param free_data_function function to be called to free the data. * @returns the new DBusTimeout object, */ DBusTimeout* _dbus_timeout_new (int interval, DBusTimeoutHandler handler, void *data, DBusFreeFunction free_data_function) { DBusTimeout *timeout; timeout = dbus_new0 (DBusTimeout, 1); if (timeout == NULL) return NULL; timeout->refcount = 1; timeout->interval = interval; timeout->handler = handler; timeout->handler_data = data; timeout->free_handler_data_function = free_data_function; timeout->enabled = TRUE; return timeout; } /** * Increments the reference count of a DBusTimeout object. * * @param timeout the timeout object. * @returns the timeout object. */ DBusTimeout * _dbus_timeout_ref (DBusTimeout *timeout) { timeout->refcount += 1; return timeout; } /** * Decrements the reference count of a DBusTimeout object * and finalizes the object if the count reaches zero. * * @param timeout the timeout object. */ void _dbus_timeout_unref (DBusTimeout *timeout) { _dbus_assert (timeout != NULL); _dbus_assert (timeout->refcount > 0); timeout->refcount -= 1; if (timeout->refcount == 0) { dbus_timeout_set_data (timeout, NULL, NULL); /* call free_data_function */ if (timeout->free_handler_data_function) (* timeout->free_handler_data_function) (timeout->handler_data); dbus_free (timeout); } } /** * Changes the timeout interval. Note that you have to disable and * re-enable the timeout using the timeout toggle function * (_dbus_connection_toggle_timeout_unlocked() etc.) to notify the * application of this change. * * @param timeout the timeout * @param interval the new interval */ void _dbus_timeout_set_interval (DBusTimeout *timeout, int interval) { _dbus_assert (interval >= 0); timeout->interval = interval; } /** * Changes the timeout's enabled-ness. Note that you should use * _dbus_connection_toggle_timeout_unlocked() etc. instead, if * the timeout is passed out to an application main loop. * i.e. you can't use this function in the D-Bus library, it's * only used in the message bus daemon implementation. * * @param timeout the timeout * @param enabled #TRUE if timeout should be enabled. */ void _dbus_timeout_set_enabled (DBusTimeout *timeout, dbus_bool_t enabled) { timeout->enabled = enabled != FALSE; } /** * @typedef DBusTimeoutList * * Opaque data type representing a list of timeouts * and a set of DBusAddTimeoutFunction/DBusRemoveTimeoutFunction. * Automatically handles removing/re-adding timeouts * when the DBusAddTimeoutFunction is updated or changed. * Holds a reference count to each timeout. * */ /** * DBusTimeoutList implementation details. All fields * are private. * */ struct DBusTimeoutList { DBusList *timeouts; /**< Timeout objects. */ DBusAddTimeoutFunction add_timeout_function; /**< Callback for adding a timeout. */ DBusRemoveTimeoutFunction remove_timeout_function; /**< Callback for removing a timeout. */ DBusTimeoutToggledFunction timeout_toggled_function; /**< Callback when timeout is enabled/disabled or changes interval */ void *timeout_data; /**< Data for timeout callbacks */ DBusFreeFunction timeout_free_data_function; /**< Free function for timeout callback data */ }; /** * Creates a new timeout list. Returns #NULL if insufficient * memory exists. * * @returns the new timeout list, or #NULL on failure. */ DBusTimeoutList* _dbus_timeout_list_new (void) { DBusTimeoutList *timeout_list; timeout_list = dbus_new0 (DBusTimeoutList, 1); if (timeout_list == NULL) return NULL; return timeout_list; } /** * Frees a DBusTimeoutList. * * @param timeout_list the timeout list. */ void _dbus_timeout_list_free (DBusTimeoutList *timeout_list) { /* free timeout_data and remove timeouts as a side effect */ _dbus_timeout_list_set_functions (timeout_list, NULL, NULL, NULL, NULL, NULL); _dbus_list_foreach (&timeout_list->timeouts, (DBusForeachFunction) _dbus_timeout_unref, NULL); _dbus_list_clear (&timeout_list->timeouts); dbus_free (timeout_list); } /** * Sets the timeout functions. This function is the "backend" * for dbus_connection_set_timeout_functions(). * * @param timeout_list the timeout list * @param add_function the add timeout function. * @param remove_function the remove timeout function. * @param toggled_function toggle notify function, or #NULL * @param data the data for those functions. * @param free_data_function the function to free the data. * @returns #FALSE if no memory * */ dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { /* Add timeouts with the new function, failing on OOM */ if (add_function != NULL) { DBusList *link; link = _dbus_list_get_first_link (&timeout_list->timeouts); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, link); if (!(* add_function) (link->data, data)) { /* remove it all again and return FALSE */ DBusList *link2; link2 = _dbus_list_get_first_link (&timeout_list->timeouts); while (link2 != link) { DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, link2); (* remove_function) (link2->data, data); link2 = next; } return FALSE; } link = next; } } /* Remove all current timeouts from previous timeout handlers */ if (timeout_list->remove_timeout_function != NULL) { _dbus_list_foreach (&timeout_list->timeouts, (DBusForeachFunction) timeout_list->remove_timeout_function, timeout_list->timeout_data); } if (timeout_list->timeout_free_data_function != NULL) (* timeout_list->timeout_free_data_function) (timeout_list->timeout_data); timeout_list->add_timeout_function = add_function; timeout_list->remove_timeout_function = remove_function; timeout_list->timeout_toggled_function = toggled_function; timeout_list->timeout_data = data; timeout_list->timeout_free_data_function = free_data_function; return TRUE; } /** * Adds a new timeout to the timeout list, invoking the * application DBusAddTimeoutFunction if appropriate. * * @param timeout_list the timeout list. * @param timeout the timeout to add. * @returns #TRUE on success, #FALSE If no memory. */ dbus_bool_t _dbus_timeout_list_add_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout) { if (!_dbus_list_append (&timeout_list->timeouts, timeout)) return FALSE; _dbus_timeout_ref (timeout); if (timeout_list->add_timeout_function != NULL) { if (!(* timeout_list->add_timeout_function) (timeout, timeout_list->timeout_data)) { _dbus_list_remove_last (&timeout_list->timeouts, timeout); _dbus_timeout_unref (timeout); return FALSE; } } return TRUE; } /** * Removes a timeout from the timeout list, invoking the * application's DBusRemoveTimeoutFunction if appropriate. * * @param timeout_list the timeout list. * @param timeout the timeout to remove. */ void _dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout) { if (!_dbus_list_remove (&timeout_list->timeouts, timeout)) _dbus_assert_not_reached ("Nonexistent timeout was removed"); if (timeout_list->remove_timeout_function != NULL) (* timeout_list->remove_timeout_function) (timeout, timeout_list->timeout_data); _dbus_timeout_unref (timeout); } /** * Sets a timeout to the given enabled state, invoking the * application's DBusTimeoutToggledFunction if appropriate. * * @param timeout_list the timeout list. * @param timeout the timeout to toggle. * @param enabled #TRUE to enable */ void _dbus_timeout_list_toggle_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout, dbus_bool_t enabled) { enabled = !!enabled; if (enabled == timeout->enabled) return; timeout->enabled = enabled; if (timeout_list->timeout_toggled_function != NULL) (* timeout_list->timeout_toggled_function) (timeout, timeout_list->timeout_data); } /** @} */ /** * @defgroup DBusTimeout DBusTimeout * @ingroup DBus * @brief Object representing a timeout * * Types and functions related to DBusTimeout. A timeout * represents a timeout that the main loop needs to monitor, * as in Qt's QTimer or GLib's g_timeout_add(). * * Use dbus_connection_set_timeout_functions() or dbus_server_set_timeout_functions() * to be notified when libdbus needs to add or remove timeouts. * * @{ */ /** * @typedef DBusTimeout * * Opaque object representing a timeout. */ /** * Gets the timeout interval. The dbus_timeout_handle() * should be called each time this interval elapses, * starting after it elapses once. * * The interval may change during the life of the * timeout; if so, the timeout will be disabled and * re-enabled (calling the "timeout toggled function") * to notify you of the change. * * @param timeout the DBusTimeout object. * @returns the interval in milliseconds. */ int dbus_timeout_get_interval (DBusTimeout *timeout) { return timeout->interval; } /** * Gets data previously set with dbus_timeout_set_data() * or #NULL if none. * * @param timeout the DBusTimeout object. * @returns previously-set data. */ void* dbus_timeout_get_data (DBusTimeout *timeout) { return timeout->data; } /** * Sets data which can be retrieved with dbus_timeout_get_data(). * Intended for use by the DBusAddTimeoutFunction and * DBusRemoveTimeoutFunction to store their own data. For example with * Qt you might store the QTimer for this timeout and with GLib * you might store a g_timeout_add result id. * * @param timeout the DBusTimeout object. * @param data the data. * @param free_data_function function to be called to free the data. */ void dbus_timeout_set_data (DBusTimeout *timeout, void *data, DBusFreeFunction free_data_function) { if (timeout->free_data_function != NULL) (* timeout->free_data_function) (timeout->data); timeout->data = data; timeout->free_data_function = free_data_function; } /** * Calls the timeout handler for this timeout. * This function should be called when the timeout * occurs. * * If this function returns #FALSE, then there wasn't * enough memory to handle the timeout. Typically just * letting the timeout fire again next time it naturally * times out is an adequate response to that problem, * but you could try to do more if you wanted. * * @param timeout the DBusTimeout object. * @returns #FALSE if there wasn't enough memory */ dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout) { return (* timeout->handler) (timeout->handler_data); } /** * Returns whether a timeout is enabled or not. If not * enabled, it should not be polled by the main loop. * * @param timeout the DBusTimeout object * @returns #TRUE if the timeout is enabled */ dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout) { return timeout->enabled; } /** @} end public API docs */ dbus-1.10.6/dbus/dbus-syntax.c0000644000175000017500000002372712602773110016132 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-syntax.c - utility functions for strings with special syntax * * Author: Simon McVittie * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-syntax.h" #include "dbus-internals.h" #include "dbus-marshal-validate.h" #include "dbus-shared.h" /** * @defgroup DBusSyntax Utility functions for strings with special syntax * @ingroup DBus * @brief Parsing D-Bus type signatures * @{ */ /** * Check an object path for validity. Remember that #NULL can always * be passed instead of a DBusError *, if you don't care about having * an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param path a potentially invalid object path, which must not be #NULL * @param error error return * @returns #TRUE if path is valid */ dbus_bool_t dbus_validate_path (const char *path, DBusError *error) { DBusString str; int len; _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_string_init_const (&str, path); len = _dbus_string_get_length (&str); /* In general, it ought to be valid... */ if (_DBUS_LIKELY (_dbus_validate_path (&str, 0, len))) return TRUE; /* slow path: string is invalid, find out why */ if (!_dbus_string_validate_utf8 (&str, 0, len)) { /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Object path was not valid UTF-8"); return FALSE; } /* FIXME: later, diagnose exactly how it was invalid */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Object path was not valid: '%s'", path); return FALSE; } /** * Check an interface name for validity. Remember that #NULL can always * be passed instead of a DBusError *, if you don't care about having * an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param name a potentially invalid interface name, which must not be #NULL * @param error error return * @returns #TRUE if name is valid */ dbus_bool_t dbus_validate_interface (const char *name, DBusError *error) { DBusString str; int len; _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_string_init_const (&str, name); len = _dbus_string_get_length (&str); /* In general, it ought to be valid... */ if (_DBUS_LIKELY (_dbus_validate_interface (&str, 0, len))) return TRUE; /* slow path: string is invalid, find out why */ if (!_dbus_string_validate_utf8 (&str, 0, len)) { /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Interface name was not valid UTF-8"); return FALSE; } /* FIXME: later, diagnose exactly how it was invalid */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Interface name was not valid: '%s'", name); return FALSE; } /** * Check a member (method/signal) name for validity. Remember that #NULL * can always be passed instead of a DBusError *, if you don't care about * having an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param name a potentially invalid member name, which must not be #NULL * @param error error return * @returns #TRUE if name is valid */ dbus_bool_t dbus_validate_member (const char *name, DBusError *error) { DBusString str; int len; _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_string_init_const (&str, name); len = _dbus_string_get_length (&str); /* In general, it ought to be valid... */ if (_DBUS_LIKELY (_dbus_validate_member (&str, 0, len))) return TRUE; /* slow path: string is invalid, find out why */ if (!_dbus_string_validate_utf8 (&str, 0, len)) { /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Member name was not valid UTF-8"); return FALSE; } /* FIXME: later, diagnose exactly how it was invalid */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Member name was not valid: '%s'", name); return FALSE; } /** * Check an error name for validity. Remember that #NULL * can always be passed instead of a DBusError *, if you don't care about * having an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param name a potentially invalid error name, which must not be #NULL * @param error error return * @returns #TRUE if name is valid */ dbus_bool_t dbus_validate_error_name (const char *name, DBusError *error) { DBusString str; int len; _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_string_init_const (&str, name); len = _dbus_string_get_length (&str); /* In general, it ought to be valid... */ if (_DBUS_LIKELY (_dbus_validate_error_name (&str, 0, len))) return TRUE; /* slow path: string is invalid, find out why */ if (!_dbus_string_validate_utf8 (&str, 0, len)) { /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Error name was not valid UTF-8"); return FALSE; } /* FIXME: later, diagnose exactly how it was invalid */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Error name was not valid: '%s'", name); return FALSE; } /** * Check a bus name for validity. Remember that #NULL * can always be passed instead of a DBusError *, if you don't care about * having an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param name a potentially invalid bus name, which must not be #NULL * @param error error return * @returns #TRUE if name is valid */ dbus_bool_t dbus_validate_bus_name (const char *name, DBusError *error) { DBusString str; int len; _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_string_init_const (&str, name); len = _dbus_string_get_length (&str); /* In general, it ought to be valid... */ if (_DBUS_LIKELY (_dbus_validate_bus_name (&str, 0, len))) return TRUE; /* slow path: string is invalid, find out why */ if (!_dbus_string_validate_utf8 (&str, 0, len)) { /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Bus name was not valid UTF-8"); return FALSE; } /* FIXME: later, diagnose exactly how it was invalid */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Bus name was not valid: '%s'", name); return FALSE; } /** * Check a string for validity. Strings on D-Bus must be valid UTF-8. * Remember that #NULL can always be passed instead of a DBusError *, * if you don't care about having an error name and message. * * This function is suitable for validating C strings, but is not suitable * for validating untrusted data from a network unless the string's length * is also checked, since it assumes that the string ends at the first zero * byte according to normal C conventions. * * @param alleged_utf8 a string to be checked, which must not be #NULL * @param error error return * @returns #TRUE if alleged_utf8 is valid UTF-8 */ dbus_bool_t dbus_validate_utf8 (const char *alleged_utf8, DBusError *error) { DBusString str; _dbus_return_val_if_fail (alleged_utf8 != NULL, FALSE); _dbus_string_init_const (&str, alleged_utf8); if (_DBUS_LIKELY (_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str)))) return TRUE; /* don't quote the actual string here, since a DBusError also needs to * be valid UTF-8 */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "String was not valid UTF-8"); return FALSE; } /** @} */ /* end of group */ dbus-1.10.6/dbus/dbus-signature.c0000644000175000017500000004644112602773110016603 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-signature.c Routines for reading recursive type signatures * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-signature.h" #include "dbus-marshal-recursive.h" #include "dbus-marshal-basic.h" #include "dbus-internals.h" #include "dbus-test.h" /** * Implementation details of #DBusSignatureIter, all fields are private */ typedef struct { const char *pos; /**< current position in the signature string */ unsigned int finished : 1; /**< true if we are at the end iter */ unsigned int in_array : 1; /**< true if we are a subiterator pointing to an array's element type */ } DBusSignatureRealIter; /** macro that checks whether a typecode is a container type */ #define TYPE_IS_CONTAINER(typecode) \ ((typecode) == DBUS_TYPE_STRUCT || \ (typecode) == DBUS_TYPE_DICT_ENTRY || \ (typecode) == DBUS_TYPE_VARIANT || \ (typecode) == DBUS_TYPE_ARRAY) /** * @defgroup DBusSignature Type signature parsing * @ingroup DBus * @brief Parsing D-Bus type signatures * @{ */ /** * Initializes a #DBusSignatureIter for reading a type signature. This * function is not safe to use on invalid signatures; be sure to * validate potentially invalid signatures with dbus_signature_validate * before using this function. * * @param iter pointer to an iterator to initialize * @param signature the type signature */ void dbus_signature_iter_init (DBusSignatureIter *iter, const char *signature) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; real_iter->pos = signature; real_iter->finished = FALSE; real_iter->in_array = FALSE; } /** * Returns the current type pointed to by the iterator. * If the iterator is pointing at a type code such as 's', then * it will be returned directly. * * However, when the parser encounters a container type start * character such as '(' for a structure, the corresponding type for * the container will be returned, e.g. DBUS_TYPE_STRUCT, not '('. * In this case, you should initialize a sub-iterator with * dbus_signature_iter_recurse() to parse the container type. * * @param iter pointer to an iterator * @returns current type (e.g. #DBUS_TYPE_STRING, #DBUS_TYPE_ARRAY) */ int dbus_signature_iter_get_current_type (const DBusSignatureIter *iter) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; return _dbus_first_type_in_signature_c_str (real_iter->pos, 0); } /** * Returns the signature of the single complete type starting at the * given iterator. * * For example, if the iterator is pointing at the start of "(ii)ii" * (which is "a struct of two ints, followed by an int, followed by an * int"), then "(ii)" would be returned. If the iterator is pointing at * one of the "i" then just that "i" would be returned. * * @param iter pointer to an iterator * @returns current signature; or #NULL if no memory. Should be freed with dbus_free() */ char * dbus_signature_iter_get_signature (const DBusSignatureIter *iter) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; DBusString str; char *ret; int pos; if (!_dbus_string_init (&str)) return NULL; pos = 0; _dbus_type_signature_next (real_iter->pos, &pos); if (!_dbus_string_append_len (&str, real_iter->pos, pos)) return NULL; if (!_dbus_string_steal_data (&str, &ret)) ret = NULL; _dbus_string_free (&str); return ret; } /** * Convenience function for returning the element type of an array; * This function allows you to avoid initializing a sub-iterator and * getting its current type. * * Undefined behavior results if you invoke this function when the * current type of the iterator is not #DBUS_TYPE_ARRAY. * * @param iter pointer to an iterator * @returns current array element type */ int dbus_signature_iter_get_element_type (const DBusSignatureIter *iter) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; _dbus_return_val_if_fail (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID); return _dbus_first_type_in_signature_c_str (real_iter->pos, 1); } /** * Skip to the next value on this "level". e.g. the next field in a * struct, the next value in an array. Returns #FALSE at the end of the * current container. * * @param iter the iterator * @returns FALSE if nothing more to read at or below this level */ dbus_bool_t dbus_signature_iter_next (DBusSignatureIter *iter) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; if (real_iter->finished) return FALSE; else { int pos; if (real_iter->in_array) { real_iter->finished = TRUE; return FALSE; } pos = 0; _dbus_type_signature_next (real_iter->pos, &pos); real_iter->pos += pos; if (*real_iter->pos == DBUS_STRUCT_END_CHAR || *real_iter->pos == DBUS_DICT_ENTRY_END_CHAR) { real_iter->finished = TRUE; return FALSE; } return *real_iter->pos != DBUS_TYPE_INVALID; } } /** * Initialize a new iterator pointing to the first type in the current * container. * * The results are undefined when calling this if the current type is * a non-container (i.e. if dbus_type_is_container() returns #FALSE * for the result of dbus_signature_iter_get_current_type()). * * @param iter the current interator * @param subiter an iterator to initialize pointing to the first child */ void dbus_signature_iter_recurse (const DBusSignatureIter *iter, DBusSignatureIter *subiter) { DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; DBusSignatureRealIter *real_sub_iter = (DBusSignatureRealIter *) subiter; _dbus_return_if_fail (dbus_type_is_container (dbus_signature_iter_get_current_type (iter))); *real_sub_iter = *real_iter; real_sub_iter->in_array = FALSE; real_sub_iter->pos++; if (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY) real_sub_iter->in_array = TRUE; } /** * Check a type signature for validity. Remember that #NULL can always * be passed instead of a DBusError*, if you don't care about having * an error name and message. * * @param signature a potentially invalid type signature * @param error error return * @returns #TRUE if signature is valid or #FALSE if an error is set */ dbus_bool_t dbus_signature_validate (const char *signature, DBusError *error) { DBusString str; DBusValidity reason; _dbus_string_init_const (&str, signature); reason = _dbus_validate_signature_with_reason (&str, 0, _dbus_string_get_length (&str)); if (reason == DBUS_VALID) return TRUE; else { dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, _dbus_validity_to_error_message (reason)); return FALSE; } } /** * Check that a type signature is both valid and contains exactly one * complete type. "One complete type" means a single basic type, * array, struct, or dictionary, though the struct or array may be * arbitrarily recursive and complex. More than one complete type * would mean for example "ii" or two integers in sequence. * * @param signature a potentially invalid type signature * @param error error return * @returns #TRUE if signature is valid and has exactly one complete type */ dbus_bool_t dbus_signature_validate_single (const char *signature, DBusError *error) { DBusSignatureIter iter; if (!dbus_signature_validate (signature, error)) return FALSE; dbus_signature_iter_init (&iter, signature); if (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID) goto lose; if (!dbus_signature_iter_next (&iter)) return TRUE; lose: dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Exactly one complete type required in signature"); return FALSE; } /** * A "container type" can contain basic types, or nested * container types. #DBUS_TYPE_INVALID is not a container type. * * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID, * to this function. The valid type-codes are defined by dbus-protocol.h * and can be checked with dbus_type_is_valid(). * * @param typecode either a valid type-code or DBUS_TYPE_INVALID * @returns #TRUE if type is a container */ dbus_bool_t dbus_type_is_container (int typecode) { /* only reasonable (non-line-noise) typecodes are allowed */ _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, FALSE); return TYPE_IS_CONTAINER (typecode); } /** * A "basic type" is a somewhat arbitrary concept, but the intent is * to include those types that are fully-specified by a single * typecode, with no additional type information or nested values. So * all numbers and strings are basic types and structs, arrays, and * variants are not basic types. #DBUS_TYPE_INVALID is not a basic * type. * * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID, * to this function. The valid type-codes are defined by dbus-protocol.h * and can be checked with dbus_type_is_valid(). * * @param typecode either a valid type-code or DBUS_TYPE_INVALID * @returns #TRUE if type is basic */ dbus_bool_t dbus_type_is_basic (int typecode) { /* only reasonable (non-line-noise) typecodes are allowed */ _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, FALSE); /* everything that isn't invalid or a container */ return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode)); } /** * Tells you whether values of this type can change length if you set * them to some other value. For this purpose, you assume that the * first byte of the old and new value would be in the same location, * so alignment padding is not a factor. * * This function is useful to determine whether * dbus_message_iter_get_fixed_array() may be used. * * Some structs are fixed-size (if they contain only fixed-size types) * but struct is not considered a fixed type for purposes of this * function. * * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID, * to this function. The valid type-codes are defined by dbus-protocol.h * and can be checked with dbus_type_is_valid(). * * @param typecode either a valid type-code or DBUS_TYPE_INVALID * @returns #FALSE if the type can occupy different lengths */ dbus_bool_t dbus_type_is_fixed (int typecode) { /* only reasonable (non-line-noise) typecodes are allowed */ _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, FALSE); switch (typecode) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: case DBUS_TYPE_UNIX_FD: return TRUE; default: return FALSE; } } /** * Return #TRUE if the argument is a valid typecode. * #DBUS_TYPE_INVALID surprisingly enough is not considered valid, and * random unknown bytes aren't either. This function is safe with * untrusted data. * * @param typecode a potential type-code * @returns #TRUE if valid */ dbus_bool_t dbus_type_is_valid (int typecode) { switch (typecode) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: case DBUS_TYPE_ARRAY: case DBUS_TYPE_STRUCT: case DBUS_TYPE_DICT_ENTRY: case DBUS_TYPE_VARIANT: case DBUS_TYPE_UNIX_FD: return TRUE; default: return FALSE; } } /** @} */ /* end of DBusSignature group */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * @ingroup DBusSignatureInternals * Unit test for DBusSignature. * * @returns #TRUE on success. */ dbus_bool_t _dbus_signature_test (void) { DBusSignatureIter iter; DBusSignatureIter subiter; DBusSignatureIter subsubiter; DBusSignatureIter subsubsubiter; const char *sig; dbus_bool_t boolres; _DBUS_STATIC_ASSERT (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter)); sig = ""; _dbus_assert (dbus_signature_validate (sig, NULL)); _dbus_assert (!dbus_signature_validate_single (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID); sig = DBUS_TYPE_STRING_AS_STRING; _dbus_assert (dbus_signature_validate (sig, NULL)); _dbus_assert (dbus_signature_validate_single (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING); sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING; _dbus_assert (dbus_signature_validate (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING); boolres = dbus_signature_iter_next (&iter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE); sig = DBUS_TYPE_UINT16_AS_STRING DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING; _dbus_assert (dbus_signature_validate (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16); boolres = dbus_signature_iter_next (&iter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT); dbus_signature_iter_recurse (&iter, &subiter); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE); sig = DBUS_TYPE_UINT16_AS_STRING DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_BYTE_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_BYTE_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING; _dbus_assert (dbus_signature_validate (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16); boolres = dbus_signature_iter_next (&iter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT); dbus_signature_iter_recurse (&iter, &subiter); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY); _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY); dbus_signature_iter_recurse (&subiter, &subsubiter); _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY); _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE); dbus_signature_iter_recurse (&subsubiter, &subsubsubiter); _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE); boolres = dbus_signature_iter_next (&subiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT); dbus_signature_iter_recurse (&subiter, &subsubiter); _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE); sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT16_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING DBUS_TYPE_VARIANT_AS_STRING; _dbus_assert (dbus_signature_validate (sig, NULL)); _dbus_assert (!dbus_signature_validate_single (sig, NULL)); dbus_signature_iter_init (&iter, sig); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY); _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY); dbus_signature_iter_recurse (&iter, &subiter); dbus_signature_iter_recurse (&subiter, &subsubiter); _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16); boolres = dbus_signature_iter_next (&subsubiter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING); boolres = dbus_signature_iter_next (&subsubiter); _dbus_assert (!boolres); boolres = dbus_signature_iter_next (&iter); _dbus_assert (boolres); _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT); boolres = dbus_signature_iter_next (&iter); _dbus_assert (!boolres); sig = DBUS_TYPE_DICT_ENTRY_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_TYPE_ARRAY_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_ARRAY_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DICT_ENTRY_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_TYPE_STRING_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_STRUCT_END_CHAR_AS_STRING DBUS_STRUCT_BEGIN_CHAR_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING; _dbus_assert (!dbus_signature_validate (sig, NULL)); return TRUE; #if 0 oom: _dbus_assert_not_reached ("out of memory"); return FALSE; #endif } #endif dbus-1.10.6/dbus/dbus-sha.h0000644000175000017500000000353512602773110015357 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sha.h SHA-1 implementation * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SHA_H #define DBUS_SHA_H #include #include #include DBUS_BEGIN_DECLS typedef struct DBusSHAContext DBusSHAContext; /** * Struct storing state of the SHA algorithm */ struct DBusSHAContext { dbus_uint32_t digest[5]; /**< Message digest */ dbus_uint32_t count_lo; /**< 64-bit bit count */ dbus_uint32_t count_hi; /**< No clue */ dbus_uint32_t data[16]; /**< SHA data buffer */ }; void _dbus_sha_init (DBusSHAContext *context); void _dbus_sha_update (DBusSHAContext *context, const DBusString *data); dbus_bool_t _dbus_sha_final (DBusSHAContext *context, DBusString *results); dbus_bool_t _dbus_sha_compute (const DBusString *data, DBusString *ascii_output); DBUS_END_DECLS #endif /* DBUS_SHA_H */ dbus-1.10.6/dbus/dbus-sha.c0000644000175000017500000007301712624705346015366 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sha.c SHA-1 implementation * * Copyright (C) 2003 Red Hat Inc. * Copyright (C) 1995 A. M. Kuchling * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-sha.h" #include "dbus-marshal-basic.h" /* for byteswap routines */ #include /* The following comments have the history of where this code * comes from. I actually copied it from GNet in GNOME CVS. * - hp@redhat.com */ /* * sha.h : Implementation of the Secure Hash Algorithm * * Part of the Python Cryptography Toolkit, version 1.0.0 * * Copyright (C) 1995, A.M. Kuchling * * Distribute and use freely; there are no restrictions on further * dissemination and usage except those imposed by the laws of your * country of residence. * */ /* SHA: NIST's Secure Hash Algorithm */ /* Based on SHA code originally posted to sci.crypt by Peter Gutmann in message <30ajo5$oe8@ccu2.auckland.ac.nz>. Modified to test for endianness on creation of SHA objects by AMK. Also, the original specification of SHA was found to have a weakness by NSA/NIST. This code implements the fixed version of SHA. */ /* Here's the first paragraph of Peter Gutmann's posting: The following is my SHA (FIPS 180) code updated to allow use of the "fixed" SHA, thanks to Jim Gillogly and an anonymous contributor for the information on what's changed in the new version. The fix is a simple change which involves adding a single rotate in the initial expansion function. It is unknown whether this is an optimal solution to the problem which was discovered in the SHA or whether it's simply a bandaid which fixes the problem with a minimum of effort (for example the reengineering of a great many Capstone chips). */ /** * @defgroup DBusSHA SHA implementation * @ingroup DBusInternals * @brief SHA-1 hash * * Types and functions related to computing SHA-1 hash. */ /** * @defgroup DBusSHAInternals SHA implementation details * @ingroup DBusInternals * @brief Internals of SHA implementation. * * The implementation of SHA-1 (see http://www.itl.nist.gov/fipspubs/fip180-1.htm). * This SHA implementation was written by A.M. Kuchling * * @{ */ #ifndef DOXYGEN_SHOULD_SKIP_THIS /* The SHA block size and message digest sizes, in bytes */ #define SHA_DATASIZE 64 #define SHA_DIGESTSIZE 20 /* The SHA f()-functions. The f1 and f3 functions can be optimized to save one boolean operation each - thanks to Rich Schroeppel, rcs@cs.arizona.edu for discovering this */ /*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) // Rounds 0-19 */ #define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */ #define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ /*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) // Rounds 40-59 */ #define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */ #define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ /* The SHA Mysterious Constants */ #define K1 0x5A827999L /* Rounds 0-19 */ #define K2 0x6ED9EBA1L /* Rounds 20-39 */ #define K3 0x8F1BBCDCL /* Rounds 40-59 */ #define K4 0xCA62C1D6L /* Rounds 60-79 */ /* SHA initial values */ #define h0init 0x67452301L #define h1init 0xEFCDAB89L #define h2init 0x98BADCFEL #define h3init 0x10325476L #define h4init 0xC3D2E1F0L /* Note that it may be necessary to add parentheses to these macros if they are to be called with expressions as arguments */ /* 32-bit rotate left - kludged with shifts */ #define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) ) /* The initial expanding function. The hash function is defined over an 80-word expanded input array W, where the first 16 are copies of the input data, and the remaining 64 are defined by W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ] This implementation generates these values on the fly in a circular buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this optimization. The updated SHA changes the expanding function by adding a rotate of 1 bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor for this information */ #define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \ W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) ) /* The prototype SHA sub-round. The fundamental sub-round is: a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data; b' = a; c' = ROTL( 30, b ); d' = c; e' = d; but this is implemented by unrolling the loop 5 times and renaming the variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration. This code is then replicated 20 times for each of the 4 functions, using the next 20 values from the W[] array each time */ #define subRound(a, b, c, d, e, f, k, data) \ ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) ) #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ /* Perform the SHA transformation. Note that this code, like MD5, seems to break some optimizing compilers due to the complexity of the expressions and the size of the basic block. It may be necessary to split it into sections, e.g. based on the four subrounds Note that this corrupts the context->data area */ static void SHATransform(dbus_uint32_t *digest, dbus_uint32_t *data) { dbus_uint32_t A, B, C, D, E; /* Local vars */ dbus_uint32_t eData[16]; /* Expanded data */ /* Set up first buffer and local data buffer */ A = digest[0]; B = digest[1]; C = digest[2]; D = digest[3]; E = digest[4]; memmove (eData, data, SHA_DATASIZE); /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ subRound (A, B, C, D, E, f1, K1, eData[0]); subRound (E, A, B, C, D, f1, K1, eData[1]); subRound (D, E, A, B, C, f1, K1, eData[2]); subRound (C, D, E, A, B, f1, K1, eData[3]); subRound (B, C, D, E, A, f1, K1, eData[4]); subRound (A, B, C, D, E, f1, K1, eData[5]); subRound (E, A, B, C, D, f1, K1, eData[6]); subRound (D, E, A, B, C, f1, K1, eData[7]); subRound (C, D, E, A, B, f1, K1, eData[8]); subRound (B, C, D, E, A, f1, K1, eData[9]); subRound (A, B, C, D, E, f1, K1, eData[10]); subRound (E, A, B, C, D, f1, K1, eData[11]); subRound (D, E, A, B, C, f1, K1, eData[12]); subRound (C, D, E, A, B, f1, K1, eData[13]); subRound (B, C, D, E, A, f1, K1, eData[14]); subRound (A, B, C, D, E, f1, K1, eData[15]); subRound (E, A, B, C, D, f1, K1, expand ( eData, 16) ); subRound (D, E, A, B, C, f1, K1, expand ( eData, 17) ); subRound (C, D, E, A, B, f1, K1, expand ( eData, 18) ); subRound (B, C, D, E, A, f1, K1, expand ( eData, 19) ); subRound (A, B, C, D, E, f2, K2, expand ( eData, 20) ); subRound (E, A, B, C, D, f2, K2, expand ( eData, 21) ); subRound (D, E, A, B, C, f2, K2, expand ( eData, 22) ); subRound (C, D, E, A, B, f2, K2, expand ( eData, 23) ); subRound (B, C, D, E, A, f2, K2, expand ( eData, 24) ); subRound (A, B, C, D, E, f2, K2, expand ( eData, 25) ); subRound (E, A, B, C, D, f2, K2, expand ( eData, 26) ); subRound (D, E, A, B, C, f2, K2, expand ( eData, 27) ); subRound (C, D, E, A, B, f2, K2, expand ( eData, 28) ); subRound (B, C, D, E, A, f2, K2, expand ( eData, 29) ); subRound (A, B, C, D, E, f2, K2, expand ( eData, 30) ); subRound (E, A, B, C, D, f2, K2, expand ( eData, 31) ); subRound (D, E, A, B, C, f2, K2, expand ( eData, 32) ); subRound (C, D, E, A, B, f2, K2, expand ( eData, 33) ); subRound (B, C, D, E, A, f2, K2, expand ( eData, 34) ); subRound (A, B, C, D, E, f2, K2, expand ( eData, 35) ); subRound (E, A, B, C, D, f2, K2, expand ( eData, 36) ); subRound (D, E, A, B, C, f2, K2, expand ( eData, 37) ); subRound (C, D, E, A, B, f2, K2, expand ( eData, 38) ); subRound (B, C, D, E, A, f2, K2, expand ( eData, 39) ); subRound (A, B, C, D, E, f3, K3, expand ( eData, 40) ); subRound (E, A, B, C, D, f3, K3, expand ( eData, 41) ); subRound (D, E, A, B, C, f3, K3, expand ( eData, 42) ); subRound (C, D, E, A, B, f3, K3, expand ( eData, 43) ); subRound (B, C, D, E, A, f3, K3, expand ( eData, 44) ); subRound (A, B, C, D, E, f3, K3, expand ( eData, 45) ); subRound (E, A, B, C, D, f3, K3, expand ( eData, 46) ); subRound (D, E, A, B, C, f3, K3, expand ( eData, 47) ); subRound (C, D, E, A, B, f3, K3, expand ( eData, 48) ); subRound (B, C, D, E, A, f3, K3, expand ( eData, 49) ); subRound (A, B, C, D, E, f3, K3, expand ( eData, 50) ); subRound (E, A, B, C, D, f3, K3, expand ( eData, 51) ); subRound (D, E, A, B, C, f3, K3, expand ( eData, 52) ); subRound (C, D, E, A, B, f3, K3, expand ( eData, 53) ); subRound (B, C, D, E, A, f3, K3, expand ( eData, 54) ); subRound (A, B, C, D, E, f3, K3, expand ( eData, 55) ); subRound (E, A, B, C, D, f3, K3, expand ( eData, 56) ); subRound (D, E, A, B, C, f3, K3, expand ( eData, 57) ); subRound (C, D, E, A, B, f3, K3, expand ( eData, 58) ); subRound (B, C, D, E, A, f3, K3, expand ( eData, 59) ); subRound (A, B, C, D, E, f4, K4, expand ( eData, 60) ); subRound (E, A, B, C, D, f4, K4, expand ( eData, 61) ); subRound (D, E, A, B, C, f4, K4, expand ( eData, 62) ); subRound (C, D, E, A, B, f4, K4, expand ( eData, 63) ); subRound (B, C, D, E, A, f4, K4, expand ( eData, 64) ); subRound (A, B, C, D, E, f4, K4, expand ( eData, 65) ); subRound (E, A, B, C, D, f4, K4, expand ( eData, 66) ); subRound (D, E, A, B, C, f4, K4, expand ( eData, 67) ); subRound (C, D, E, A, B, f4, K4, expand ( eData, 68) ); subRound (B, C, D, E, A, f4, K4, expand ( eData, 69) ); subRound (A, B, C, D, E, f4, K4, expand ( eData, 70) ); subRound (E, A, B, C, D, f4, K4, expand ( eData, 71) ); subRound (D, E, A, B, C, f4, K4, expand ( eData, 72) ); subRound (C, D, E, A, B, f4, K4, expand ( eData, 73) ); subRound (B, C, D, E, A, f4, K4, expand ( eData, 74) ); subRound (A, B, C, D, E, f4, K4, expand ( eData, 75) ); subRound (E, A, B, C, D, f4, K4, expand ( eData, 76) ); subRound (D, E, A, B, C, f4, K4, expand ( eData, 77) ); subRound (C, D, E, A, B, f4, K4, expand ( eData, 78) ); subRound (B, C, D, E, A, f4, K4, expand ( eData, 79) ); /* Build message digest */ digest[0] += A; digest[1] += B; digest[2] += C; digest[3] += D; digest[4] += E; } /* When run on a little-endian CPU we need to perform byte reversal on an array of longwords. */ #ifdef WORDS_BIGENDIAN #define swap_words(buffer, byte_count) #else static void swap_words (dbus_uint32_t *buffer, int byte_count) { byte_count /= sizeof (dbus_uint32_t); while (byte_count--) { *buffer = DBUS_UINT32_SWAP_LE_BE (*buffer); ++buffer; } } #endif static void sha_init (DBusSHAContext *context) { /* Set the h-vars to their initial values */ context->digest[0] = h0init; context->digest[1] = h1init; context->digest[2] = h2init; context->digest[3] = h3init; context->digest[4] = h4init; /* Initialise bit count */ context->count_lo = context->count_hi = 0; } static void sha_append (DBusSHAContext *context, const unsigned char *buffer, unsigned int count) { dbus_uint32_t tmp; unsigned int dataCount; /* Update bitcount */ tmp = context->count_lo; if (( context->count_lo = tmp + ( ( dbus_uint32_t) count << 3) ) < tmp) context->count_hi++; /* Carry from low to high */ context->count_hi += count >> 29; /* Get count of bytes already in data */ dataCount = (int) (tmp >> 3) & 0x3F; /* Handle any leading odd-sized chunks */ if (dataCount) { unsigned char *p = (unsigned char *) context->data + dataCount; dataCount = SHA_DATASIZE - dataCount; if (count < dataCount) { memmove (p, buffer, count); return; } memmove (p, buffer, dataCount); swap_words (context->data, SHA_DATASIZE); SHATransform (context->digest, context->data); buffer += dataCount; count -= dataCount; } /* Process data in SHA_DATASIZE chunks */ while (count >= SHA_DATASIZE) { memmove (context->data, buffer, SHA_DATASIZE); swap_words (context->data, SHA_DATASIZE); SHATransform (context->digest, context->data); buffer += SHA_DATASIZE; count -= SHA_DATASIZE; } /* Handle any remaining bytes of data. */ memmove (context->data, buffer, count); } /* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern 1 0* (64-bit count of bits processed, MSB-first) */ static void sha_finish (DBusSHAContext *context, unsigned char digest[20]) { int count; unsigned char *data_p; /* Compute number of bytes mod 64 */ count = (int) context->count_lo; count = (count >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ data_p = (unsigned char *) context->data + count; *data_p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = SHA_DATASIZE - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset (data_p, 0, count); swap_words (context->data, SHA_DATASIZE); SHATransform (context->digest, context->data); /* Now fill the next block with 56 bytes */ memset (context->data, 0, SHA_DATASIZE - 8); } else /* Pad block to 56 bytes */ memset (data_p, 0, count - 8); /* Append length in bits and transform */ context->data[14] = context->count_hi; context->data[15] = context->count_lo; swap_words (context->data, SHA_DATASIZE - 8); SHATransform (context->digest, context->data); swap_words (context->digest, SHA_DIGESTSIZE); memmove (digest, context->digest, SHA_DIGESTSIZE); } /** @} */ /* End of internals */ /** * @addtogroup DBusSHA * * @{ */ /** * Initializes the SHA context. * * @param context an uninitialized context, typically on the stack. */ void _dbus_sha_init (DBusSHAContext *context) { sha_init (context); } /** * Feeds more data into an existing shasum computation. * * @param context the SHA context * @param data the additional data to hash */ void _dbus_sha_update (DBusSHAContext *context, const DBusString *data) { unsigned int inputLen; const unsigned char *input; input = (const unsigned char*) _dbus_string_get_const_data (data); inputLen = _dbus_string_get_length (data); sha_append (context, input, inputLen); } /** * SHA finalization. Ends an SHA message-digest operation, writing the * the message digest and zeroing the context. The results are * returned as a raw 20-byte digest, not as the ascii-hex-digits * string form of the digest. * * @param context the SHA context * @param results string to append the 20-byte SHA digest to * @returns #FALSE if not enough memory to append the digest * */ dbus_bool_t _dbus_sha_final (DBusSHAContext *context, DBusString *results) { unsigned char digest[20]; sha_finish (context, digest); if (!_dbus_string_append_len (results, digest, 20)) return FALSE; /* some kind of security paranoia, though it seems pointless * to me given the nonzeroed stuff flying around */ _DBUS_ZERO(*context); return TRUE; } /** * Computes the ASCII hex-encoded shasum of the given data and * appends it to the output string. * * @param data input data to be hashed * @param ascii_output string to append ASCII shasum to * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_sha_compute (const DBusString *data, DBusString *ascii_output) { DBusSHAContext context; DBusString digest; _dbus_sha_init (&context); _dbus_sha_update (&context, data); if (!_dbus_string_init (&digest)) return FALSE; if (!_dbus_sha_final (&context, &digest)) goto error; if (!_dbus_string_hex_encode (&digest, 0, ascii_output, _dbus_string_get_length (ascii_output))) goto error; _dbus_string_free (&digest); return TRUE; error: _dbus_string_free (&digest); return FALSE; } /** @} */ /* end of exported functions */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include static dbus_bool_t check_sha_binary (const unsigned char *input, int input_len, const char *expected) { DBusString input_str; DBusString expected_str; DBusString results; _dbus_string_init_const_len (&input_str, input, input_len); _dbus_string_init_const (&expected_str, expected); if (!_dbus_string_init (&results)) _dbus_assert_not_reached ("no memory for SHA-1 results"); if (!_dbus_sha_compute (&input_str, &results)) _dbus_assert_not_reached ("no memory for SHA-1 results"); if (!_dbus_string_equal (&expected_str, &results)) { _dbus_warn ("Expected hash %s got %s for SHA-1 sum\n", expected, _dbus_string_get_const_data (&results)); _dbus_string_free (&results); return FALSE; } _dbus_string_free (&results); return TRUE; } static dbus_bool_t check_sha_str (const char *input, const char *expected) { return check_sha_binary (input, strlen (input), expected); } static dbus_bool_t decode_compact_string (const DBusString *line, DBusString *decoded) { int n_bits; dbus_bool_t current_b; int offset; int next; long val; int length_bytes; offset = 0; next = 0; if (!_dbus_string_parse_int (line, offset, &val, &next)) { fprintf (stderr, "could not parse length at start of compact string: %s\n", _dbus_string_get_const_data (line)); return FALSE; } _dbus_string_skip_blank (line, next, &next); offset = next; if (!_dbus_string_parse_int (line, offset, &val, &next)) { fprintf (stderr, "could not parse start bit 'b' in compact string: %s\n", _dbus_string_get_const_data (line)); return FALSE; } if (!(val == 0 || val == 1)) { fprintf (stderr, "the value 'b' must be 0 or 1, see sha-1/Readme.txt\n"); return FALSE; } _dbus_string_skip_blank (line, next, &next); current_b = val; n_bits = 0; while (next < _dbus_string_get_length (line)) { int total_bits; offset = next; if (_dbus_string_get_byte (line, offset) == '^') break; if (!_dbus_string_parse_int (line, offset, &val, &next)) { fprintf (stderr, "could not parse bit count in compact string\n"); return FALSE; } /* We now append "val" copies of "current_b" bits to the string */ total_bits = n_bits + val; while (n_bits < total_bits) { int byte_containing_next_bit = n_bits / 8; int bit_containing_next_bit = 7 - (n_bits % 8); unsigned char old_byte; if (byte_containing_next_bit >= _dbus_string_get_length (decoded)) { if (!_dbus_string_set_length (decoded, byte_containing_next_bit + 1)) _dbus_assert_not_reached ("no memory to extend to next byte"); } old_byte = _dbus_string_get_byte (decoded, byte_containing_next_bit); old_byte |= current_b << bit_containing_next_bit; #if 0 printf ("Appending bit %d to byte %d at bit %d resulting in byte 0x%x\n", current_b, byte_containing_next_bit, bit_containing_next_bit, old_byte); #endif _dbus_string_set_byte (decoded, byte_containing_next_bit, old_byte); ++n_bits; } _dbus_string_skip_blank (line, next, &next); current_b = !current_b; } length_bytes = (n_bits / 8 + ((n_bits % 8) ? 1 : 0)); if (_dbus_string_get_length (decoded) != length_bytes) { fprintf (stderr, "Expected length %d bytes %d bits for compact string, got %d bytes\n", length_bytes, n_bits, _dbus_string_get_length (decoded)); return FALSE; } else return TRUE; } static dbus_bool_t get_next_expected_result (DBusString *results, DBusString *result) { DBusString line; dbus_bool_t retval; retval = FALSE; if (!_dbus_string_init (&line)) _dbus_assert_not_reached ("no memory"); next_iteration: while (_dbus_string_pop_line (results, &line)) { _dbus_string_delete_leading_blanks (&line); if (_dbus_string_get_length (&line) == 0) goto next_iteration; else if (_dbus_string_starts_with_c_str (&line, "#")) goto next_iteration; else if (_dbus_string_starts_with_c_str (&line, "H>")) { /* don't print */ } else if (_dbus_string_starts_with_c_str (&line, "D>") || _dbus_string_starts_with_c_str (&line, "")) { printf ("SHA-1: %s\n", _dbus_string_get_const_data (&line)); if (_dbus_string_find (&line, 0, "Type 3", NULL)) { /* See sha-1/Readme.txt - the "Type 3" tests are * random seeds, rather than data to be hashed. * we'd have to do a little bit more implementation * to use those tests. */ printf (" (ending tests due to Type 3 tests seen - this is normal)\n"); break; } } else if (_dbus_string_starts_with_c_str (&line, "D>") || _dbus_string_starts_with_c_str (&line, " * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SERVER_WIN_H #define DBUS_SERVER_WIN_H #include #include DBUS_BEGIN_DECLS /* add definitions here */ DBUS_END_DECLS #endif /* DBUS_SERVER_WIN_H */ dbus-1.10.6/dbus/dbus-server-win.c0000644000175000017500000000613412602773110016676 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-win.c Server implementation for WIN network protocols. * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * Copyright (C) 2007 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-server-win.h" #include "dbus-server-socket.h" /** * @defgroup DBusServerWin DBusServer implementations for Windows * @ingroup DBusInternals * @brief Implementation details of DBusServer on Windows * * @{ */ /** * Tries to interpret the address entry in a platform-specific * way, creating a platform-specific server type if appropriate. * Sets error if the result is not OK. * * @param entry an address entry * @param server_p location to store a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "autolaunch") == 0) { const char *host = "localhost"; const char *bind = "localhost"; const char *port = "0"; const char *family = "ipv4"; const char *scope = dbus_address_entry_get_value (entry, "scope"); if (_dbus_daemon_is_session_bus_address_published (scope)) return DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED; *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, family, error, FALSE); if (*server_p) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); (*server_p)->published_address = _dbus_daemon_publish_session_bus_address ((*server_p)->address, scope); return DBUS_SERVER_LISTEN_OK; } else { // make sure no handle is open _dbus_daemon_unpublish_session_bus_address (); _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } } /** @} */ dbus-1.10.6/dbus/dbus-server-unix.h0000644000175000017500000000255112602773110017070 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-unix.h Server implementation for Unix network protocols. * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SERVER_UNIX_H #define DBUS_SERVER_UNIX_H #include #include DBUS_BEGIN_DECLS DBusServer* _dbus_server_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error); DBUS_END_DECLS #endif /* DBUS_SERVER_UNIX_H */ dbus-1.10.6/dbus/dbus-server-unix.c0000644000175000017500000002566212602773110017073 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-unix.c Server implementation for Unix network protocols. * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-server-unix.h" #include "dbus-server-socket.h" #include "dbus-server-launchd.h" #include "dbus-transport-unix.h" #include "dbus-connection-internal.h" #include "dbus-sysdeps-unix.h" #include "dbus-string.h" /** * @defgroup DBusServerUnix DBusServer implementations for UNIX * @ingroup DBusInternals * @brief Implementation details of DBusServer on UNIX * * @{ */ /** * Tries to interpret the address entry in a platform-specific * way, creating a platform-specific server type if appropriate. * Sets error if the result is not OK. * * @param entry an address entry * @param server_p location to store a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "unix") == 0) { const char *path = dbus_address_entry_get_value (entry, "path"); const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); const char *abstract = dbus_address_entry_get_value (entry, "abstract"); const char *runtime = dbus_address_entry_get_value (entry, "runtime"); int mutually_exclusive_modes = 0; mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) + (abstract != NULL) + (runtime != NULL); if (mutually_exclusive_modes < 1) { _dbus_set_bad_address(error, "unix", "path or tmpdir or abstract or runtime", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if (mutually_exclusive_modes > 1) { _dbus_set_bad_address(error, NULL, NULL, "cannot specify two of \"path\", \"tmpdir\", \"abstract\" and \"runtime\" at the same time"); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if (runtime != NULL) { DBusString full_path; DBusString filename; const char *runtimedir; if (strcmp (runtime, "yes") != 0) { _dbus_set_bad_address(error, NULL, NULL, "if given, the only value allowed for \"runtime\" is \"yes\""); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR"); if (runtimedir == NULL) { dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set"); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } _dbus_string_init_const (&filename, "bus"); if (!_dbus_string_init (&full_path)) { _DBUS_SET_OOM (error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_append (&full_path, runtimedir) || !_dbus_concat_dir_and_file (&full_path, &filename)) { _dbus_string_free (&full_path); _DBUS_SET_OOM (error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } /* We can safely use filesystem sockets in the runtime directory, * and they are preferred because they can be bind-mounted between * Linux containers. */ *server_p = _dbus_server_new_for_domain_socket ( _dbus_string_get_const_data (&full_path), FALSE, error); _dbus_string_free (&full_path); } else if (tmpdir != NULL) { DBusString full_path; DBusString filename; if (!_dbus_string_init (&full_path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_init (&filename)) { _dbus_string_free (&full_path); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_append (&filename, "dbus-")) { _dbus_string_free (&full_path); _dbus_string_free (&filename); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_generate_random_ascii (&filename, 10, error)) { _dbus_string_free (&full_path); _dbus_string_free (&filename); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_append (&full_path, tmpdir) || !_dbus_concat_dir_and_file (&full_path, &filename)) { _dbus_string_free (&full_path); _dbus_string_free (&filename); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } /* Always use abstract namespace if possible with tmpdir */ *server_p = _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), #ifdef HAVE_ABSTRACT_SOCKETS TRUE, #else FALSE, #endif error); _dbus_string_free (&full_path); _dbus_string_free (&filename); } else { if (path) *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); else *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); } if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else if (strcmp (method, "systemd") == 0) { int i, n; DBusSocket *fds; DBusString address; n = _dbus_listen_systemd_sockets (&fds, error); if (n < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_init (&address)) goto systemd_oom; for (i = 0; i < n; i++) { if (i > 0) { if (!_dbus_string_append (&address, ";")) goto systemd_oom; } if (!_dbus_append_address_from_socket (fds[i], &address, error)) goto systemd_err; } *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error); if (*server_p == NULL) goto systemd_err; dbus_free (fds); return DBUS_SERVER_LISTEN_OK; systemd_oom: _DBUS_SET_OOM (error); systemd_err: for (i = 0; i < n; i++) { _dbus_close_socket (fds[i], NULL); } dbus_free (fds); _dbus_string_free (&address); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } #ifdef DBUS_ENABLE_LAUNCHD else if (strcmp (method, "launchd") == 0) { const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); if (launchd_env_var == NULL) { _dbus_set_bad_address (error, "launchd", "env", NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } *server_p = _dbus_server_new_for_launchd (launchd_env_var, error); if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } #endif else { /* If we don't handle the method, we return NULL with the * error unset */ _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } } /** * Creates a new server listening on the given Unix domain socket. * * @param path the path for the domain socket. * @param abstract #TRUE to use abstract socket namespace * @param error location to store reason for failure. * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error) { DBusServer *server; DBusSocket listen_fd; DBusString address; char *path_copy; DBusString path_str; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } _dbus_string_init_const (&path_str, path); if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_address_append_escaped (&address, &path_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (abstract) { path_copy = NULL; } else { path_copy = _dbus_strdup (path); if (path_copy == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } } listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error); if (listen_fd.fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_1; } server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error); if (server == NULL) { goto failed_2; } if (path_copy != NULL) _dbus_server_socket_own_filename(server, path_copy); _dbus_string_free (&address); return server; failed_2: _dbus_close_socket (listen_fd, NULL); failed_1: dbus_free (path_copy); failed_0: _dbus_string_free (&address); return NULL; } /** @} */ dbus-1.10.6/dbus/dbus-uuidgen.h0000644000175000017500000000362712602773110016246 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-uuidgen.h The guts of the dbus-uuidgen binary live in libdbus, in this file. * * Copyright (C) 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef DBUS_INSIDE_DBUS_H #error "You can't include dbus-uuidgen.h in the public header dbus.h" #endif #ifndef DBUS_UUIDGEN_H #define DBUS_UUIDGEN_H #include #include DBUS_BEGIN_DECLS DBUS_PRIVATE_EXPORT dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename, char **uuid_p, dbus_bool_t create_if_not_found, DBusError *error); dbus_bool_t dbus_internal_do_not_use_ensure_uuid (const char *filename, char **uuid_p, DBusError *error); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_create_uuid (char **uuid_p, DBusError *error); DBUS_END_DECLS #endif /* DBUS_UUIDGEN_H */ dbus-1.10.6/dbus/dbus-uuidgen.c0000644000175000017500000000670312602773110016237 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-uuidgen.c The guts of the dbus-uuidgen binary live in libdbus, in this file. * * Copyright (C) 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-uuidgen.h" #include "dbus-internals.h" #include "dbus-string.h" #include "dbus-protocol.h" #ifdef DBUS_WIN #error "dbus-uuidgen should not be needed on Windows" #endif /** * @defgroup DBusInternalsUuidgen dbus-uuidgen implementation * @ingroup DBusInternals * @brief Functions for dbus-uuidgen binary * * These are not considered part of the ABI, and if you call them * you will get screwed by future changes. * * @{ */ static dbus_bool_t return_uuid (DBusGUID *uuid, char **uuid_p, DBusError *error) { if (uuid_p) { DBusString encoded; if (!_dbus_string_init (&encoded)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_uuid_encode (uuid, &encoded) || !_dbus_string_steal_data (&encoded, uuid_p)) { _DBUS_SET_OOM (error); _dbus_string_free (&encoded); return FALSE; } _dbus_string_free (&encoded); } return TRUE; } /** * For use by the dbus-uuidgen binary ONLY, do not call this. * We can and will change this function without modifying * the libdbus soname. * * @param filename the file or #NULL for the machine ID file * @param uuid_p out param to return the uuid * @param create_if_not_found whether to create it if not already there * @param error error return * @returns #FALSE if error is set */ dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename, char **uuid_p, dbus_bool_t create_if_not_found, DBusError *error) { DBusGUID uuid; if (filename) { DBusString filename_str; _dbus_string_init_const (&filename_str, filename); if (!_dbus_read_uuid_file (&filename_str, &uuid, create_if_not_found, error)) goto error; } else { if (!_dbus_read_local_machine_uuid (&uuid, create_if_not_found, error)) goto error; } if (!return_uuid(&uuid, uuid_p, error)) goto error; return TRUE; error: _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } /** * @param uuid_p out param to return the uuid * @param error location to store reason for failure * @returns #TRUE on success */ dbus_bool_t _dbus_create_uuid (char **uuid_p, DBusError *error) { DBusGUID uuid; if (!_dbus_generate_uuid (&uuid, error)) return FALSE; return return_uuid (&uuid, uuid_p, error); } /** @} */ dbus-1.10.6/dbus/dbus-server-socket.h0000644000175000017500000000500612602773110017373 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-socket.h Server implementation for sockets * * Copyright (C) 2002, 2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SERVER_SOCKET_H #define DBUS_SERVER_SOCKET_H #include #include #include DBUS_BEGIN_DECLS DBusServer* _dbus_server_new_for_socket (DBusSocket *fds, int n_fds, const DBusString *address, DBusNonceFile *noncefile, DBusError *error); DBusServer* _dbus_server_new_for_autolaunch (const DBusString *address, DBusError *error); DBUS_PRIVATE_EXPORT DBusServer* _dbus_server_new_for_tcp_socket (const char *host, const char *bind, const char *port, const char *family, DBusError *error, dbus_bool_t use_nonce); DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); void _dbus_server_socket_own_filename (DBusServer *server, char *filename); DBUS_END_DECLS #endif /* DBUS_SERVER_SOCKET_H */ dbus-1.10.6/dbus/dbus-server-socket.c0000644000175000017500000004057112602773110017374 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-socket.c Server implementation for sockets * * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-server-socket.h" #include "dbus-transport-socket.h" #include "dbus-connection-internal.h" #include "dbus-memory.h" #include "dbus-nonce.h" #include "dbus-string.h" /** * @defgroup DBusServerSocket DBusServer implementations for SOCKET * @ingroup DBusInternals * @brief Implementation details of DBusServer on SOCKET * * @{ */ /** * * Opaque object representing a Socket server implementation. */ typedef struct DBusServerSocket DBusServerSocket; /** * Implementation details of DBusServerSocket. All members * are private. */ struct DBusServerSocket { DBusServer base; /**< Parent class members. */ int n_fds; /**< Number of active file handles */ DBusSocket *fds; /**< File descriptor or DBUS_SOCKET_INVALID if disconnected. */ DBusWatch **watch; /**< File descriptor watch. */ char *socket_name; /**< Name of domain socket, to unlink if appropriate */ DBusNonceFile *noncefile; /**< Nonce file used to authenticate clients */ }; static void socket_finalize (DBusServer *server) { DBusServerSocket *socket_server = (DBusServerSocket*) server; int i; _dbus_server_finalize_base (server); for (i = 0 ; i < socket_server->n_fds ; i++) if (socket_server->watch[i]) { _dbus_watch_unref (socket_server->watch[i]); socket_server->watch[i] = NULL; } dbus_free (socket_server->fds); dbus_free (socket_server->watch); dbus_free (socket_server->socket_name); if (socket_server->noncefile) _dbus_noncefile_delete (socket_server->noncefile, NULL); dbus_free (socket_server->noncefile); dbus_free (server); } /* Return value is just for memory, not other failures. */ static dbus_bool_t handle_new_client_fd_and_unlock (DBusServer *server, DBusSocket client_fd) { DBusConnection *connection; DBusTransport *transport; DBusNewConnectionFunction new_connection_function; void *new_connection_data; _dbus_verbose ("Creating new client connection with fd %" DBUS_SOCKET_FORMAT "\n", _dbus_socket_printable (client_fd)); HAVE_LOCK_CHECK (server); if (!_dbus_set_socket_nonblocking (client_fd, NULL)) { SERVER_UNLOCK (server); return TRUE; } transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL); if (transport == NULL) { _dbus_close_socket (client_fd, NULL); SERVER_UNLOCK (server); return FALSE; } if (!_dbus_transport_set_auth_mechanisms (transport, (const char **) server->auth_mechanisms)) { _dbus_transport_unref (transport); SERVER_UNLOCK (server); return FALSE; } /* note that client_fd is now owned by the transport, and will be * closed on transport disconnection/finalization */ connection = _dbus_connection_new_for_transport (transport); _dbus_transport_unref (transport); transport = NULL; /* now under the connection lock */ if (connection == NULL) { SERVER_UNLOCK (server); return FALSE; } /* See if someone wants to handle this new connection, self-referencing * for paranoia. */ new_connection_function = server->new_connection_function; new_connection_data = server->new_connection_data; _dbus_server_ref_unlocked (server); SERVER_UNLOCK (server); if (new_connection_function) { (* new_connection_function) (server, connection, new_connection_data); } dbus_server_unref (server); /* If no one grabbed a reference, the connection will die. */ _dbus_connection_close_if_only_one_ref (connection); dbus_connection_unref (connection); return TRUE; } static dbus_bool_t socket_handle_watch (DBusWatch *watch, unsigned int flags, void *data) { DBusServer *server = data; DBusServerSocket *socket_server = data; #ifndef DBUS_DISABLE_ASSERT int i; dbus_bool_t found = FALSE; #endif SERVER_LOCK (server); #ifndef DBUS_DISABLE_ASSERT for (i = 0 ; i < socket_server->n_fds ; i++) { if (socket_server->watch[i] == watch) found = TRUE; } _dbus_assert (found); #endif _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); if (flags & DBUS_WATCH_READABLE) { DBusSocket client_fd; DBusSocket listen_fd; int saved_errno; listen_fd = _dbus_watch_get_socket (watch); if (socket_server->noncefile) client_fd = _dbus_accept_with_noncefile (listen_fd, socket_server->noncefile); else client_fd = _dbus_accept (listen_fd); saved_errno = _dbus_save_socket_errno (); if (!_dbus_socket_is_valid (client_fd)) { /* EINTR handled for us */ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) _dbus_verbose ("No client available to accept after all\n"); else _dbus_verbose ("Failed to accept a client connection: %s\n", _dbus_strerror (saved_errno)); SERVER_UNLOCK (server); } else { if (!handle_new_client_fd_and_unlock (server, client_fd)) _dbus_verbose ("Rejected client connection due to lack of memory\n"); } } if (flags & DBUS_WATCH_ERROR) _dbus_verbose ("Error on server listening socket\n"); if (flags & DBUS_WATCH_HANGUP) _dbus_verbose ("Hangup on server listening socket\n"); return TRUE; } static void socket_disconnect (DBusServer *server) { DBusServerSocket *socket_server = (DBusServerSocket*) server; int i; HAVE_LOCK_CHECK (server); for (i = 0 ; i < socket_server->n_fds ; i++) { if (socket_server->watch[i]) { _dbus_server_remove_watch (server, socket_server->watch[i]); _dbus_watch_invalidate (socket_server->watch[i]); _dbus_watch_unref (socket_server->watch[i]); socket_server->watch[i] = NULL; } _dbus_close_socket (socket_server->fds[i], NULL); _dbus_socket_invalidate (&socket_server->fds[i]); } if (socket_server->socket_name != NULL) { DBusString tmp; _dbus_string_init_const (&tmp, socket_server->socket_name); _dbus_delete_file (&tmp, NULL); } if (server->published_address) _dbus_daemon_unpublish_session_bus_address(); HAVE_LOCK_CHECK (server); } static const DBusServerVTable socket_vtable = { socket_finalize, socket_disconnect }; /** * Creates a new server listening on the given file descriptor. The * file descriptor should be nonblocking (use * _dbus_set_fd_nonblocking() to make it so). The file descriptor * should be listening for connections, that is, listen() should have * been successfully invoked on it. The server will use accept() to * accept new client connections. * * @param fds list of file descriptors. * @param n_fds number of file descriptors * @param address the server's address * @param noncefile to be used for authentication (NULL if not needed) * @param error location to store reason for failure * @returns the new server, or #NULL on OOM or other error. * */ DBusServer* _dbus_server_new_for_socket (DBusSocket *fds, int n_fds, const DBusString *address, DBusNonceFile *noncefile, DBusError *error) { DBusServerSocket *socket_server; DBusServer *server; int i; socket_server = dbus_new0 (DBusServerSocket, 1); if (socket_server == NULL) goto failed_0; socket_server->noncefile = noncefile; socket_server->fds = dbus_new (DBusSocket, n_fds); if (!socket_server->fds) goto failed_0; socket_server->watch = dbus_new0 (DBusWatch *, n_fds); if (!socket_server->watch) goto failed_1; for (i = 0 ; i < n_fds ; i++) { DBusWatch *watch; watch = _dbus_watch_new (_dbus_socket_get_pollable (fds[i]), DBUS_WATCH_READABLE, TRUE, socket_handle_watch, socket_server, NULL); if (watch == NULL) goto failed_2; socket_server->n_fds++; socket_server->fds[i] = fds[i]; socket_server->watch[i] = watch; } if (!_dbus_server_init_base (&socket_server->base, &socket_vtable, address, error)) goto failed_2; server = (DBusServer*)socket_server; SERVER_LOCK (server); for (i = 0 ; i < n_fds ; i++) { if (!_dbus_server_add_watch (&socket_server->base, socket_server->watch[i])) { int j; for (j = 0 ; j < i ; j++) _dbus_server_remove_watch (server, socket_server->watch[j]); SERVER_UNLOCK (server); _dbus_server_finalize_base (&socket_server->base); goto failed_2; } } SERVER_UNLOCK (server); _dbus_server_trace_ref (&socket_server->base, 0, 1, "new_for_socket"); return (DBusServer*) socket_server; failed_2: for (i = 0 ; i < n_fds ; i++) { if (socket_server->watch[i] != NULL) { _dbus_watch_unref (socket_server->watch[i]); socket_server->watch[i] = NULL; } } dbus_free (socket_server->watch); failed_1: dbus_free (socket_server->fds); failed_0: dbus_free (socket_server); if (error != NULL && !dbus_error_is_set (error)) _DBUS_SET_OOM (error); return NULL; } /** * Creates a new server listening on TCP. * If host is NULL, it will default to localhost. * If bind is NULL, it will default to the value for the host * parameter, and if that is NULL, then localhost * If bind is a hostname, it will be resolved and will listen * on all returned addresses. * If family is NULL, hostname resolution will try all address * families, otherwise it can be ipv4 or ipv6 to restrict the * addresses considered. * * @param host the hostname to report for the listen address * @param bind the hostname to listen on * @param port the port to listen on or 0 to let the OS choose * @param family * @param error location to store reason for failure. * @param use_nonce whether to use a nonce for low-level authentication (nonce-tcp transport) or not (tcp transport) * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_tcp_socket (const char *host, const char *bind, const char *port, const char *family, DBusError *error, dbus_bool_t use_nonce) { DBusServer *server; DBusSocket *listen_fds = NULL; int nlisten_fds = 0, i; DBusString address; DBusString host_str; DBusString port_str; DBusNonceFile *noncefile; _DBUS_ASSERT_ERROR_IS_CLEAR (error); noncefile = NULL; if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_init (&port_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (host == NULL) host = "localhost"; if (port == NULL) port = "0"; if (bind == NULL) bind = host; else if (strcmp (bind, "*") == 0) bind = NULL; nlisten_fds =_dbus_listen_tcp_socket (bind, port, family, &port_str, &listen_fds, error); if (nlisten_fds <= 0) { _DBUS_ASSERT_ERROR_IS_SET(error); goto failed_1; } _dbus_string_init_const (&host_str, host); if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") || !_dbus_address_append_escaped (&address, &host_str) || !_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (family && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (use_nonce) { noncefile = dbus_new0 (DBusNonceFile, 1); if (noncefile == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (!_dbus_noncefile_create (noncefile, error)) goto failed_3; if (!_dbus_string_append (&address, ",noncefile=") || !_dbus_address_append_escaped (&address, _dbus_noncefile_get_path (noncefile))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_4; } } server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile, error); if (server == NULL) { if (noncefile != NULL) goto failed_4; else goto failed_2; } _dbus_string_free (&port_str); _dbus_string_free (&address); dbus_free(listen_fds); return server; failed_4: _dbus_noncefile_delete (noncefile, NULL); failed_3: dbus_free (noncefile); failed_2: for (i = 0 ; i < nlisten_fds ; i++) _dbus_close_socket (listen_fds[i], NULL); dbus_free(listen_fds); failed_1: _dbus_string_free (&port_str); failed_0: _dbus_string_free (&address); return NULL; } /** * Tries to interpret the address entry for various socket-related * addresses (well, currently only tcp and nonce-tcp). * * Sets error if the result is not OK. * * @param entry an address entry * @param server_p a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "tcp") == 0 || strcmp (method, "nonce-tcp") == 0) { const char *host; const char *port; const char *bind; const char *family; host = dbus_address_entry_get_value (entry, "host"); bind = dbus_address_entry_get_value (entry, "bind"); port = dbus_address_entry_get_value (entry, "port"); family = dbus_address_entry_get_value (entry, "family"); *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, family, error, strcmp (method, "nonce-tcp") == 0 ? TRUE : FALSE); if (*server_p) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } } /** * This is a bad hack since it's really unix domain socket * specific. Also, the function weirdly adopts ownership * of the passed-in string. * * @param server a socket server * @param filename socket filename to report/delete * */ void _dbus_server_socket_own_filename (DBusServer *server, char *filename) { DBusServerSocket *socket_server = (DBusServerSocket*) server; socket_server->socket_name = filename; } /** @} */ dbus-1.10.6/dbus/dbus-server-protected.h0000644000175000017500000001613512602773110020101 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-protected.h Used by subclasses of DBusServer object (internal to D-Bus implementation) * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SERVER_PROTECTED_H #define DBUS_SERVER_PROTECTED_H #include #include #include #include #include #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusServerVTable DBusServerVTable; /** * Virtual table to be implemented by all server "subclasses" */ struct DBusServerVTable { void (* finalize) (DBusServer *server); /**< The finalize method must free the server. */ void (* disconnect) (DBusServer *server); /**< Disconnect this server. */ }; /** * @ingroup DBusServerInternals * Internals of DBusServer object */ struct DBusServer { DBusAtomic refcount; /**< Reference count. */ const DBusServerVTable *vtable; /**< Virtual methods for this instance. */ DBusRMutex *mutex; /**< Lock on the server object */ DBusGUID guid; /**< Globally unique ID of server */ DBusString guid_hex; /**< Hex-encoded version of GUID */ DBusWatchList *watches; /**< Our watches */ DBusTimeoutList *timeouts; /**< Our timeouts */ char *address; /**< Address this server is listening on. */ dbus_bool_t published_address; /**< flag which indicates that server has published its bus address. */ int max_connections; /**< Max number of connections allowed at once. */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ DBusNewConnectionFunction new_connection_function; /**< Callback to invoke when a new connection is created. */ void *new_connection_data; /**< Data for new connection callback */ DBusFreeFunction new_connection_free_data_function; /**< Callback to invoke to free new_connection_data * when server is finalized or data is replaced. */ char **auth_mechanisms; /**< Array of allowed authentication mechanisms */ unsigned int disconnected : 1; /**< TRUE if we are disconnected. */ #ifndef DBUS_DISABLE_CHECKS unsigned int have_server_lock : 1; /**< Does someone have the server mutex locked */ #endif }; dbus_bool_t _dbus_server_init_base (DBusServer *server, const DBusServerVTable *vtable, const DBusString *address, DBusError *error); void _dbus_server_finalize_base (DBusServer *server); dbus_bool_t _dbus_server_add_watch (DBusServer *server, DBusWatch *watch); void _dbus_server_remove_watch (DBusServer *server, DBusWatch *watch); DBUS_PRIVATE_EXPORT void _dbus_server_toggle_all_watches (DBusServer *server, dbus_bool_t enabled); dbus_bool_t _dbus_server_add_timeout (DBusServer *server, DBusTimeout *timeout); void _dbus_server_remove_timeout (DBusServer *server, DBusTimeout *timeout); void _dbus_server_toggle_timeout (DBusServer *server, DBusTimeout *timeout, dbus_bool_t enabled); DBUS_PRIVATE_EXPORT void _dbus_server_ref_unlocked (DBusServer *server); DBUS_PRIVATE_EXPORT void _dbus_server_unref_unlocked (DBusServer *server); typedef enum { DBUS_SERVER_LISTEN_NOT_HANDLED, /**< we aren't in charge of this address type */ DBUS_SERVER_LISTEN_OK, /**< we set up the listen */ DBUS_SERVER_LISTEN_BAD_ADDRESS, /**< malformed address */ DBUS_SERVER_LISTEN_DID_NOT_CONNECT, /**< well-formed address but failed to set it up */ DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED /**< address is already used */ } DBusServerListenResult; DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); #ifdef DBUS_ENABLE_VERBOSE_MODE void _dbus_server_trace_ref (DBusServer *server, int old_refcount, int new_refcount, const char *why); #else #define _dbus_server_trace_ref(s,o,n,w) \ do \ {\ (void) (o); \ (void) (n); \ } while (0) #endif #ifdef DBUS_DISABLE_CHECKS #define TOOK_LOCK_CHECK(server) #define RELEASING_LOCK_CHECK(server) #define HAVE_LOCK_CHECK(server) #else #define TOOK_LOCK_CHECK(server) do { \ _dbus_assert (!(server)->have_server_lock); \ (server)->have_server_lock = TRUE; \ } while (0) #define RELEASING_LOCK_CHECK(server) do { \ _dbus_assert ((server)->have_server_lock); \ (server)->have_server_lock = FALSE; \ } while (0) #define HAVE_LOCK_CHECK(server) _dbus_assert ((server)->have_server_lock) /* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ #endif #define TRACE_LOCKS 0 #define SERVER_LOCK(server) do { \ if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \ _dbus_rmutex_lock ((server)->mutex); \ TOOK_LOCK_CHECK (server); \ } while (0) #define SERVER_UNLOCK(server) do { \ if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n"); } \ RELEASING_LOCK_CHECK (server); \ _dbus_rmutex_unlock ((server)->mutex); \ } while (0) DBUS_END_DECLS #endif /* DBUS_SERVER_PROTECTED_H */ dbus-1.10.6/dbus/dbus-server-debug-pipe.h0000644000175000017500000000410012602773110020116 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-debug-pipe.h In-proc debug server implementation * * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SERVER_DEBUG_PIPE_H #define DBUS_SERVER_DEBUG_PIPE_H #include #include #include DBUS_BEGIN_DECLS DBusServer* _dbus_server_debug_pipe_new (const char *server_name, DBusError *error); DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, DBusError *error); DBusServerListenResult _dbus_server_listen_debug_pipe (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); DBusTransportOpenResult _dbus_transport_open_debug_pipe (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error); DBUS_END_DECLS #endif /* DBUS_SERVER_DEBUG_PIPE_H */ dbus-1.10.6/dbus/dbus-server-debug-pipe.c0000644000175000017500000002664212602773110020130 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server-debug-pipe.c In-proc debug server implementation * * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2003, 2004 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-server-debug-pipe.h" #include "dbus-transport-socket.h" #include "dbus-connection-internal.h" #include "dbus-hash.h" #include "dbus-string.h" #include "dbus-protocol.h" #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * @defgroup DBusServerDebugPipe DBusServerDebugPipe * @ingroup DBusInternals * @brief In-process pipe debug server used in unit tests. * * Types and functions related to DBusServerDebugPipe. * This is used for unit testing. * * @{ */ /** * Opaque object representing a debug server implementation. */ typedef struct DBusServerDebugPipe DBusServerDebugPipe; /** * Implementation details of DBusServerDebugPipe. All members * are private. */ struct DBusServerDebugPipe { DBusServer base; /**< Parent class members. */ char *name; /**< Server name. */ dbus_bool_t disconnected; /**< TRUE if disconnect has been called */ }; /* FIXME not threadsafe (right now the test suite doesn't use threads anyhow ) */ static DBusHashTable *server_pipe_hash; static int server_pipe_hash_refcount = 0; static dbus_bool_t pipe_hash_ref (void) { if (!server_pipe_hash) { _dbus_assert (server_pipe_hash_refcount == 0); server_pipe_hash = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, NULL); if (!server_pipe_hash) return FALSE; } server_pipe_hash_refcount = 1; return TRUE; } static void pipe_hash_unref (void) { _dbus_assert (server_pipe_hash != NULL); _dbus_assert (server_pipe_hash_refcount > 0); server_pipe_hash_refcount -= 1; if (server_pipe_hash_refcount == 0) { _dbus_hash_table_unref (server_pipe_hash); server_pipe_hash = NULL; } } static void debug_finalize (DBusServer *server) { DBusServerDebugPipe *debug_server = (DBusServerDebugPipe*) server; pipe_hash_unref (); _dbus_server_finalize_base (server); dbus_free (debug_server->name); dbus_free (server); } static void debug_disconnect (DBusServer *server) { ((DBusServerDebugPipe*)server)->disconnected = TRUE; } static DBusServerVTable debug_vtable = { debug_finalize, debug_disconnect }; /** * Creates a new debug server using an in-process pipe * * @param server_name the name of the server. * @param error address where an error can be returned. * @returns a new server, or #NULL on failure. */ DBusServer* _dbus_server_debug_pipe_new (const char *server_name, DBusError *error) { DBusServerDebugPipe *debug_server; DBusString address; DBusString name_str; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!pipe_hash_ref ()) return NULL; if (_dbus_hash_table_lookup_string (server_pipe_hash, server_name) != NULL) { dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, NULL); pipe_hash_unref (); return NULL; } debug_server = dbus_new0 (DBusServerDebugPipe, 1); if (debug_server == NULL) goto nomem_0; if (!_dbus_string_init (&address)) goto nomem_1; _dbus_string_init_const (&name_str, server_name); if (!_dbus_string_append (&address, "debug-pipe:name=") || !_dbus_address_append_escaped (&address, &name_str)) goto nomem_2; debug_server->name = _dbus_strdup (server_name); if (debug_server->name == NULL) goto nomem_2; if (!_dbus_server_init_base (&debug_server->base, &debug_vtable, &address, error)) goto fail_3; if (!_dbus_hash_table_insert_string (server_pipe_hash, debug_server->name, debug_server)) goto nomem_4; _dbus_string_free (&address); /* server keeps the pipe hash ref */ _dbus_server_trace_ref (&debug_server->base, 0, 1, "debug_pipe_new"); return (DBusServer *)debug_server; nomem_4: _dbus_server_finalize_base (&debug_server->base); fail_3: dbus_free (debug_server->name); nomem_2: _dbus_string_free (&address); nomem_1: dbus_free (debug_server); nomem_0: pipe_hash_unref (); if (error != NULL && !dbus_error_is_set (error)) _DBUS_SET_OOM (error); return NULL; } /** * Creates the client-side transport for * a debug-pipe connection connected to the * given debug-pipe server name. * * @param server_name name of server to connect to * @param error address where an error can be returned. * @returns #NULL on no memory or transport */ DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, DBusError *error) { DBusTransport *client_transport; DBusTransport *server_transport; DBusConnection *connection; DBusSocket client_fd, server_fd; DBusServer *server; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (server_pipe_hash == NULL) { dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); return NULL; } server = _dbus_hash_table_lookup_string (server_pipe_hash, server_name); if (server == NULL || ((DBusServerDebugPipe*)server)->disconnected) { dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); return NULL; } if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_append (&address, "debug-pipe:name=") || !_dbus_string_append (&address, server_name)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&address); return NULL; } if (!_dbus_socketpair (&client_fd, &server_fd, FALSE, NULL)) { _dbus_verbose ("failed to create full duplex pipe\n"); dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe"); _dbus_string_free (&address); return NULL; } client_transport = _dbus_transport_new_for_socket (client_fd, NULL, &address); if (client_transport == NULL) { _dbus_close_socket (client_fd, NULL); _dbus_close_socket (server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&address); return NULL; } _dbus_string_free (&address); _dbus_socket_invalidate (&client_fd); server_transport = _dbus_transport_new_for_socket (server_fd, &server->guid_hex, NULL); if (server_transport == NULL) { _dbus_transport_unref (client_transport); _dbus_close_socket (server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } _dbus_socket_invalidate (&server_fd); if (!_dbus_transport_set_auth_mechanisms (server_transport, (const char**) server->auth_mechanisms)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_transport_unref (server_transport); _dbus_transport_unref (client_transport); return NULL; } connection = _dbus_connection_new_for_transport (server_transport); _dbus_transport_unref (server_transport); server_transport = NULL; if (connection == NULL) { _dbus_transport_unref (client_transport); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } /* See if someone wants to handle this new connection, * self-referencing for paranoia */ if (server->new_connection_function) { dbus_server_ref (server); (* server->new_connection_function) (server, connection, server->new_connection_data); dbus_server_unref (server); } /* If no one grabbed a reference, the connection will die, * and the client transport will get an immediate disconnect */ _dbus_connection_close_if_only_one_ref (connection); dbus_connection_unref (connection); return client_transport; } /** * Tries to interpret the address entry as a debug pipe entry. * * Sets error if the result is not OK. * * @param entry an address entry * @param server_p location to store a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_debug_pipe (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address(error, "debug-pipe", "name", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } *server_p = _dbus_server_debug_pipe_new (name, error); if (*server_p) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } } /** * Opens a debug pipe transport, used in the test suite. * * @param entry the address entry to try opening as debug-pipe * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_debug_pipe (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address (error, "debug-pipe", "name", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_debug_pipe_new (name, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } } /** @} */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-server.c0000644000175000017500000010646712602773110016115 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server.c DBusServer object * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-server.h" #include "dbus-server-unix.h" #include "dbus-server-socket.h" #include "dbus-string.h" #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-server-debug-pipe.h" #endif #include "dbus-address.h" #include "dbus-protocol.h" /** * @defgroup DBusServer DBusServer * @ingroup DBus * @brief Server that listens for new connections. * * A DBusServer represents a server that other applications * can connect to. Each connection from another application * is represented by a #DBusConnection. * * @todo Thread safety hasn't been tested much for #DBusServer * @todo Need notification to apps of disconnection, may matter for some transports */ /** * @defgroup DBusServerInternals DBusServer implementation details * @ingroup DBusInternals * @brief Implementation details of DBusServer * * @{ */ #ifndef _dbus_server_trace_ref void _dbus_server_trace_ref (DBusServer *server, int old_refcount, int new_refcount, const char *why) { static int enabled = -1; _dbus_trace_ref ("DBusServer", server, old_refcount, new_refcount, why, "DBUS_SERVER_TRACE", &enabled); } #endif /* this is a little fragile since it assumes the address doesn't * already have a guid, but it shouldn't */ static char* copy_address_with_guid_appended (const DBusString *address, const DBusString *guid_hex) { DBusString with_guid; char *retval; if (!_dbus_string_init (&with_guid)) return NULL; if (!_dbus_string_copy (address, 0, &with_guid, _dbus_string_get_length (&with_guid)) || !_dbus_string_append (&with_guid, ",guid=") || !_dbus_string_copy (guid_hex, 0, &with_guid, _dbus_string_get_length (&with_guid))) { _dbus_string_free (&with_guid); return NULL; } retval = NULL; _dbus_string_steal_data (&with_guid, &retval); _dbus_string_free (&with_guid); return retval; /* may be NULL if steal_data failed */ } /** * Initializes the members of the DBusServer base class. * Chained up to by subclass constructors. * * @param server the server. * @param vtable the vtable for the subclass. * @param address the server's address * @param error location to store reason for failure * @returns #TRUE on success. */ dbus_bool_t _dbus_server_init_base (DBusServer *server, const DBusServerVTable *vtable, const DBusString *address, DBusError *error) { server->vtable = vtable; #ifdef DBUS_DISABLE_ASSERT _dbus_atomic_inc (&server->refcount); #else { dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount); _dbus_assert (old_refcount == 0); } #endif server->address = NULL; server->watches = NULL; server->timeouts = NULL; server->published_address = FALSE; if (!_dbus_string_init (&server->guid_hex)) { _DBUS_SET_OOM (error); return FALSE; } if (!_dbus_generate_uuid (&server->guid, error)) goto failed; if (!_dbus_uuid_encode (&server->guid, &server->guid_hex)) goto oom; server->address = copy_address_with_guid_appended (address, &server->guid_hex); if (server->address == NULL) goto oom; _dbus_rmutex_new_at_location (&server->mutex); if (server->mutex == NULL) goto oom; server->watches = _dbus_watch_list_new (); if (server->watches == NULL) goto oom; server->timeouts = _dbus_timeout_list_new (); if (server->timeouts == NULL) goto oom; _dbus_data_slot_list_init (&server->slot_list); _dbus_verbose ("Initialized server on address %s\n", server->address); return TRUE; oom: _DBUS_SET_OOM (error); failed: _dbus_rmutex_free_at_location (&server->mutex); server->mutex = NULL; if (server->watches) { _dbus_watch_list_free (server->watches); server->watches = NULL; } if (server->timeouts) { _dbus_timeout_list_free (server->timeouts); server->timeouts = NULL; } if (server->address) { dbus_free (server->address); server->address = NULL; } _dbus_string_free (&server->guid_hex); return FALSE; } /** * Finalizes the members of the DBusServer base class. * Chained up to by subclass finalizers. * * @param server the server. */ void _dbus_server_finalize_base (DBusServer *server) { /* We don't have the lock, but nobody should be accessing * concurrently since they don't have a ref */ #ifndef DBUS_DISABLE_CHECKS _dbus_assert (!server->have_server_lock); #endif _dbus_assert (server->disconnected); /* calls out to application code... */ _dbus_data_slot_list_free (&server->slot_list); dbus_server_set_new_connection_function (server, NULL, NULL, NULL); _dbus_watch_list_free (server->watches); _dbus_timeout_list_free (server->timeouts); _dbus_rmutex_free_at_location (&server->mutex); dbus_free (server->address); dbus_free_string_array (server->auth_mechanisms); _dbus_string_free (&server->guid_hex); } /** Function to be called in protected_change_watch() with refcount held */ typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, DBusWatch *watch); /** Function to be called in protected_change_watch() with refcount held */ typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, DBusWatch *watch); /** Function to be called in protected_change_watch() with refcount held */ typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, DBusWatch *watch, dbus_bool_t enabled); static dbus_bool_t protected_change_watch (DBusServer *server, DBusWatch *watch, DBusWatchAddFunction add_function, DBusWatchRemoveFunction remove_function, DBusWatchToggleFunction toggle_function, dbus_bool_t enabled) { DBusWatchList *watches; dbus_bool_t retval; HAVE_LOCK_CHECK (server); /* This isn't really safe or reasonable; a better pattern is the "do * everything, then drop lock and call out" one; but it has to be * propagated up through all callers */ watches = server->watches; if (watches) { server->watches = NULL; _dbus_server_ref_unlocked (server); SERVER_UNLOCK (server); if (add_function) retval = (* add_function) (watches, watch); else if (remove_function) { retval = TRUE; (* remove_function) (watches, watch); } else { retval = TRUE; (* toggle_function) (watches, watch, enabled); } SERVER_LOCK (server); server->watches = watches; _dbus_server_unref_unlocked (server); return retval; } else return FALSE; } /** * Adds a watch for this server, chaining out to application-provided * watch handlers. * * @param server the server. * @param watch the watch to add. */ dbus_bool_t _dbus_server_add_watch (DBusServer *server, DBusWatch *watch) { HAVE_LOCK_CHECK (server); return protected_change_watch (server, watch, _dbus_watch_list_add_watch, NULL, NULL, FALSE); } /** * Removes a watch previously added with _dbus_server_remove_watch(). * * @param server the server. * @param watch the watch to remove. */ void _dbus_server_remove_watch (DBusServer *server, DBusWatch *watch) { HAVE_LOCK_CHECK (server); protected_change_watch (server, watch, NULL, _dbus_watch_list_remove_watch, NULL, FALSE); } /** * Toggles all watch and notifies app via server's * DBusWatchToggledFunction if available. * * @param server the server. * @param enabled whether to enable or disable */ void _dbus_server_toggle_all_watches (DBusServer *server, dbus_bool_t enabled) { _dbus_watch_list_toggle_all_watches (server->watches, enabled); } /** Function to be called in protected_change_timeout() with refcount held */ typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, DBusTimeout *timeout); /** Function to be called in protected_change_timeout() with refcount held */ typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, DBusTimeout *timeout); /** Function to be called in protected_change_timeout() with refcount held */ typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, DBusTimeout *timeout, dbus_bool_t enabled); static dbus_bool_t protected_change_timeout (DBusServer *server, DBusTimeout *timeout, DBusTimeoutAddFunction add_function, DBusTimeoutRemoveFunction remove_function, DBusTimeoutToggleFunction toggle_function, dbus_bool_t enabled) { DBusTimeoutList *timeouts; dbus_bool_t retval; HAVE_LOCK_CHECK (server); /* This isn't really safe or reasonable; a better pattern is the "do everything, then * drop lock and call out" one; but it has to be propagated up through all callers */ timeouts = server->timeouts; if (timeouts) { server->timeouts = NULL; _dbus_server_ref_unlocked (server); SERVER_UNLOCK (server); if (add_function) retval = (* add_function) (timeouts, timeout); else if (remove_function) { retval = TRUE; (* remove_function) (timeouts, timeout); } else { retval = TRUE; (* toggle_function) (timeouts, timeout, enabled); } SERVER_LOCK (server); server->timeouts = timeouts; _dbus_server_unref_unlocked (server); return retval; } else return FALSE; } /** * Adds a timeout for this server, chaining out to * application-provided timeout handlers. The timeout should be * repeatedly handled with dbus_timeout_handle() at its given interval * until it is removed. * * @param server the server. * @param timeout the timeout to add. */ dbus_bool_t _dbus_server_add_timeout (DBusServer *server, DBusTimeout *timeout) { return protected_change_timeout (server, timeout, _dbus_timeout_list_add_timeout, NULL, NULL, FALSE); } /** * Removes a timeout previously added with _dbus_server_add_timeout(). * * @param server the server. * @param timeout the timeout to remove. */ void _dbus_server_remove_timeout (DBusServer *server, DBusTimeout *timeout) { protected_change_timeout (server, timeout, NULL, _dbus_timeout_list_remove_timeout, NULL, FALSE); } /** * Toggles a timeout and notifies app via server's * DBusTimeoutToggledFunction if available. It's an error to call this * function on a timeout that was not previously added. * * @param server the server. * @param timeout the timeout to toggle. * @param enabled whether to enable or disable */ void _dbus_server_toggle_timeout (DBusServer *server, DBusTimeout *timeout, dbus_bool_t enabled) { protected_change_timeout (server, timeout, NULL, NULL, _dbus_timeout_list_toggle_timeout, enabled); } /** * Like dbus_server_ref() but does not acquire the lock (must already be held) * * @param server the server. */ void _dbus_server_ref_unlocked (DBusServer *server) { dbus_int32_t old_refcount; _dbus_assert (server != NULL); HAVE_LOCK_CHECK (server); old_refcount = _dbus_atomic_inc (&server->refcount); _dbus_assert (old_refcount > 0); _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref_unlocked"); } /** * Like dbus_server_unref() but does not acquire the lock (must already be held) * * @param server the server. */ void _dbus_server_unref_unlocked (DBusServer *server) { dbus_int32_t old_refcount; /* Keep this in sync with dbus_server_unref */ _dbus_assert (server != NULL); HAVE_LOCK_CHECK (server); old_refcount = _dbus_atomic_dec (&server->refcount); _dbus_assert (old_refcount > 0); _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref_unlocked"); if (old_refcount == 1) { _dbus_assert (server->disconnected); SERVER_UNLOCK (server); _dbus_assert (server->vtable->finalize != NULL); (* server->vtable->finalize) (server); } } /** @} */ /** * @addtogroup DBusServer * * @{ */ /** * @typedef DBusServer * * An opaque object representing a server that listens for * connections from other applications. Each time a connection * is made, a new DBusConnection is created and made available * via an application-provided DBusNewConnectionFunction. * The DBusNewConnectionFunction is provided with * dbus_server_set_new_connection_function(). * */ static const struct { DBusServerListenResult (* func) (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); } listen_funcs[] = { { _dbus_server_listen_socket } , { _dbus_server_listen_platform_specific } #ifdef DBUS_ENABLE_EMBEDDED_TESTS , { _dbus_server_listen_debug_pipe } #endif }; /** * Listens for new connections on the given address. If there are * multiple semicolon-separated address entries in the address, tries * each one and listens on the first one that works. * * Returns #NULL and sets error if listening fails for any reason. * Otherwise returns a new #DBusServer. * dbus_server_set_new_connection_function(), * dbus_server_set_watch_functions(), and * dbus_server_set_timeout_functions() should be called immediately to * render the server fully functional. * * To free the server, applications must call first * dbus_server_disconnect() and then dbus_server_unref(). * * @param address the address of this server. * @param error location to store reason for failure. * @returns a new #DBusServer, or #NULL on failure. * */ DBusServer* dbus_server_listen (const char *address, DBusError *error) { DBusServer *server; DBusAddressEntry **entries; int len, i; DBusError first_connect_error = DBUS_ERROR_INIT; dbus_bool_t handled_once; _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); if (!dbus_parse_address (address, &entries, &len, error)) return NULL; server = NULL; handled_once = FALSE; for (i = 0; i < len; i++) { int j; for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) { DBusServerListenResult result; DBusError tmp_error = DBUS_ERROR_INIT; result = (* listen_funcs[j].func) (entries[i], &server, &tmp_error); if (result == DBUS_SERVER_LISTEN_OK) { _dbus_assert (server != NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED) { _dbus_assert (server == NULL); dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, "Address '%s' already used", dbus_address_entry_get_method (entries[0])); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); dbus_move_error (&tmp_error, error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* keep trying addresses */ } else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); if (!dbus_error_is_set (&first_connect_error)) dbus_move_error (&tmp_error, &first_connect_error); else dbus_error_free (&tmp_error); handled_once = TRUE; /* keep trying addresses */ } } _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (error); } out: if (!handled_once) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (len > 0) dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Unknown address type '%s'", dbus_address_entry_get_method (entries[0])); else dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Empty address '%s'", address); } dbus_address_entries_free (entries); if (server == NULL) { _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || dbus_error_is_set (error)); if (error && dbus_error_is_set (error)) { /* already set the error */ } else { /* didn't set the error but either error should be * NULL or first_connect_error should be set. */ _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); dbus_move_error (&first_connect_error, error); } _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return server; } } /** * Increments the reference count of a DBusServer. * * @param server the server. * @returns the server */ DBusServer * dbus_server_ref (DBusServer *server) { dbus_int32_t old_refcount; _dbus_return_val_if_fail (server != NULL, NULL); old_refcount = _dbus_atomic_inc (&server->refcount); #ifndef DBUS_DISABLE_CHECKS if (_DBUS_UNLIKELY (old_refcount <= 0)) { _dbus_atomic_dec (&server->refcount); _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, _DBUS_FUNCTION_NAME, "old_refcount > 0", __FILE__, __LINE__); return NULL; } #endif _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref"); return server; } /** * Decrements the reference count of a DBusServer. Finalizes the * server if the reference count reaches zero. * * The server must be disconnected before the refcount reaches zero. * * @param server the server. */ void dbus_server_unref (DBusServer *server) { dbus_int32_t old_refcount; /* keep this in sync with unref_unlocked */ _dbus_return_if_fail (server != NULL); old_refcount = _dbus_atomic_dec (&server->refcount); #ifndef DBUS_DISABLE_CHECKS if (_DBUS_UNLIKELY (old_refcount <= 0)) { /* undo side-effect first * please do not try to simplify the code here by using * _dbus_atomic_get(), why we don't use it is * because it issues another atomic operation even though * DBUS_DISABLE_CHECKS defined. * Bug: https://bugs.freedesktop.org/show_bug.cgi?id=68303 */ _dbus_atomic_inc (&server->refcount); _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, _DBUS_FUNCTION_NAME, "old_refcount > 0", __FILE__, __LINE__); return; } #endif _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref"); if (old_refcount == 1) { /* lock not held! */ _dbus_assert (server->disconnected); _dbus_assert (server->vtable->finalize != NULL); (* server->vtable->finalize) (server); } } /** * Releases the server's address and stops listening for * new clients. If called more than once, only the first * call has an effect. Does not modify the server's * reference count. * * @param server the server. */ void dbus_server_disconnect (DBusServer *server) { _dbus_return_if_fail (server != NULL); dbus_server_ref (server); SERVER_LOCK (server); _dbus_assert (server->vtable->disconnect != NULL); if (!server->disconnected) { /* this has to be first so recursive calls to disconnect don't happen */ server->disconnected = TRUE; (* server->vtable->disconnect) (server); } SERVER_UNLOCK (server); dbus_server_unref (server); } /** * Returns #TRUE if the server is still listening for new connections. * * @param server the server. */ dbus_bool_t dbus_server_get_is_connected (DBusServer *server) { dbus_bool_t retval; _dbus_return_val_if_fail (server != NULL, FALSE); SERVER_LOCK (server); retval = !server->disconnected; SERVER_UNLOCK (server); return retval; } /** * Returns the address of the server, as a newly-allocated * string which must be freed by the caller. * * @param server the server * @returns the address or #NULL if no memory */ char* dbus_server_get_address (DBusServer *server) { char *retval; _dbus_return_val_if_fail (server != NULL, NULL); SERVER_LOCK (server); retval = _dbus_strdup (server->address); SERVER_UNLOCK (server); return retval; } /** * Returns the unique ID of the server, as a newly-allocated * string which must be freed by the caller. This ID is * normally used by clients to tell when two #DBusConnection * would be equivalent (because the server address passed * to dbus_connection_open() will have the same guid in the * two cases). dbus_connection_open() can re-use an existing * connection with the same ID instead of opening a new * connection. * * This is an ID unique to each #DBusServer. Remember that * a #DBusServer represents only one mode of connecting, * so e.g. a bus daemon can listen on multiple addresses * which will mean it has multiple #DBusServer each with * their own ID. * * The ID is not a UUID in the sense of RFC4122; the details * are explained in the D-Bus specification. * * @param server the server * @returns the id of the server or #NULL if no memory */ char* dbus_server_get_id (DBusServer *server) { char *retval; _dbus_return_val_if_fail (server != NULL, NULL); SERVER_LOCK (server); retval = NULL; _dbus_string_copy_data (&server->guid_hex, &retval); SERVER_UNLOCK (server); return retval; } /** * Sets a function to be used for handling new connections. The given * function is passed each new connection as the connection is * created. If the new connection function increments the connection's * reference count, the connection will stay alive. Otherwise, the * connection will be unreferenced and closed. The new connection * function may also close the connection itself, which is considered * good form if the connection is not wanted. * * The connection here is private in the sense of * dbus_connection_open_private(), so if the new connection function * keeps a reference it must arrange for the connection to be closed. * i.e. libdbus does not own this connection once the new connection * function takes a reference. * * @param server the server. * @param function a function to handle new connections. * @param data data to pass to the new connection handler. * @param free_data_function function to free the data. */ void dbus_server_set_new_connection_function (DBusServer *server, DBusNewConnectionFunction function, void *data, DBusFreeFunction free_data_function) { DBusFreeFunction old_free_function; void *old_data; _dbus_return_if_fail (server != NULL); SERVER_LOCK (server); old_free_function = server->new_connection_free_data_function; old_data = server->new_connection_data; server->new_connection_function = function; server->new_connection_data = data; server->new_connection_free_data_function = free_data_function; SERVER_UNLOCK (server); if (old_free_function != NULL) (* old_free_function) (old_data); } /** * Sets the watch functions for the server. These functions are * responsible for making the application's main loop aware of file * descriptors that need to be monitored for events. * * This function behaves exactly like dbus_connection_set_watch_functions(); * see the documentation for that routine. * * @param server the server. * @param add_function function to begin monitoring a new descriptor. * @param remove_function function to stop monitoring a descriptor. * @param toggled_function function to notify when the watch is enabled/disabled * @param data data to pass to add_function and remove_function. * @param free_data_function function to be called to free the data. * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_server_set_watch_functions (DBusServer *server, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { dbus_bool_t result; DBusWatchList *watches; _dbus_return_val_if_fail (server != NULL, FALSE); SERVER_LOCK (server); watches = server->watches; server->watches = NULL; if (watches) { SERVER_UNLOCK (server); result = _dbus_watch_list_set_functions (watches, add_function, remove_function, toggled_function, data, free_data_function); SERVER_LOCK (server); } else { _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); result = FALSE; } server->watches = watches; SERVER_UNLOCK (server); return result; } /** * Sets the timeout functions for the server. These functions are * responsible for making the application's main loop aware of timeouts. * * This function behaves exactly like dbus_connection_set_timeout_functions(); * see the documentation for that routine. * * @param server the server. * @param add_function function to add a timeout. * @param remove_function function to remove a timeout. * @param toggled_function function to notify when the timeout is enabled/disabled * @param data data to pass to add_function and remove_function. * @param free_data_function function to be called to free the data. * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_server_set_timeout_functions (DBusServer *server, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { dbus_bool_t result; DBusTimeoutList *timeouts; _dbus_return_val_if_fail (server != NULL, FALSE); SERVER_LOCK (server); timeouts = server->timeouts; server->timeouts = NULL; if (timeouts) { SERVER_UNLOCK (server); result = _dbus_timeout_list_set_functions (timeouts, add_function, remove_function, toggled_function, data, free_data_function); SERVER_LOCK (server); } else { _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); result = FALSE; } server->timeouts = timeouts; SERVER_UNLOCK (server); return result; } /** * Sets the authentication mechanisms that this server offers to * clients, as a #NULL-terminated array of mechanism names. This * function only affects connections created after it is * called. Pass #NULL instead of an array to use all available * mechanisms (this is the default behavior). * * The D-Bus specification describes some of the supported mechanisms. * * @param server the server * @param mechanisms #NULL-terminated array of mechanisms * @returns #FALSE if no memory */ dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer *server, const char **mechanisms) { char **copy; _dbus_return_val_if_fail (server != NULL, FALSE); SERVER_LOCK (server); if (mechanisms != NULL) { copy = _dbus_dup_string_array (mechanisms); if (copy == NULL) { SERVER_UNLOCK (server); return FALSE; } } else copy = NULL; dbus_free_string_array (server->auth_mechanisms); server->auth_mechanisms = copy; SERVER_UNLOCK (server); return TRUE; } static DBusDataSlotAllocator slot_allocator = _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (server_slots)); /** * Allocates an integer ID to be used for storing application-specific * data on any DBusServer. The allocated ID may then be used * with dbus_server_set_data() and dbus_server_get_data(). * The slot must be initialized with -1. If a nonnegative * slot is passed in, the refcount is incremented on that * slot, rather than creating a new slot. * * The allocated slot is global, i.e. all DBusServer objects will have * a slot with the given integer ID reserved. * * @param slot_p address of global variable storing the slot ID * @returns #FALSE on no memory */ dbus_bool_t dbus_server_allocate_data_slot (dbus_int32_t *slot_p) { return _dbus_data_slot_allocator_alloc (&slot_allocator, slot_p); } /** * Deallocates a global ID for server data slots. * dbus_server_get_data() and dbus_server_set_data() * may no longer be used with this slot. * Existing data stored on existing DBusServer objects * will be freed when the server is finalized, * but may not be retrieved (and may only be replaced * if someone else reallocates the slot). * * @param slot_p address of the slot to deallocate */ void dbus_server_free_data_slot (dbus_int32_t *slot_p) { _dbus_return_if_fail (*slot_p >= 0); _dbus_data_slot_allocator_free (&slot_allocator, slot_p); } /** * Stores a pointer on a DBusServer, along * with an optional function to be used for freeing * the data when the data is set again, or when * the server is finalized. The slot number * must have been allocated with dbus_server_allocate_data_slot(). * * @param server the server * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t dbus_server_set_data (DBusServer *server, int slot, void *data, DBusFreeFunction free_data_func) { DBusFreeFunction old_free_func; void *old_data; dbus_bool_t retval; _dbus_return_val_if_fail (server != NULL, FALSE); SERVER_LOCK (server); retval = _dbus_data_slot_list_set (&slot_allocator, &server->slot_list, slot, data, free_data_func, &old_free_func, &old_data); SERVER_UNLOCK (server); if (retval) { /* Do the actual free outside the server lock */ if (old_free_func) (* old_free_func) (old_data); } return retval; } /** * Retrieves data previously set with dbus_server_set_data(). * The slot must still be allocated (must not have been freed). * * @param server the server * @param slot the slot to get data from * @returns the data, or #NULL if not found */ void* dbus_server_get_data (DBusServer *server, int slot) { void *res; _dbus_return_val_if_fail (server != NULL, NULL); SERVER_LOCK (server); res = _dbus_data_slot_list_get (&slot_allocator, &server->slot_list, slot); SERVER_UNLOCK (server); return res; } /** @} */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include dbus_bool_t _dbus_server_test (void) { const char *valid_addresses[] = { "tcp:port=1234", "tcp:host=localhost,port=1234", "tcp:host=localhost,port=1234;tcp:port=5678", #ifdef DBUS_UNIX "unix:path=./boogie", "tcp:port=1234;unix:path=./boogie", #endif }; DBusServer *server; int i; for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) { DBusError error = DBUS_ERROR_INIT; char *address; char *id; server = dbus_server_listen (valid_addresses[i], &error); if (server == NULL) { _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); dbus_error_free (&error); _dbus_assert_not_reached ("Failed to listen for valid address."); } id = dbus_server_get_id (server); _dbus_assert (id != NULL); address = dbus_server_get_address (server); _dbus_assert (address != NULL); if (strstr (address, id) == NULL) { _dbus_warn ("server id '%s' is not in the server address '%s'\n", id, address); _dbus_assert_not_reached ("bad server id or address"); } dbus_free (id); dbus_free (address); dbus_server_disconnect (server); dbus_server_unref (server); } return TRUE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-resources.h0000644000175000017500000000471512602773110016617 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-resources.h Resource tracking/limits * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_RESOURCES_H #define DBUS_RESOURCES_H #include #include #include DBUS_BEGIN_DECLS typedef struct DBusCounter DBusCounter; typedef void (* DBusCounterNotifyFunction) (DBusCounter *counter, void *user_data); DBusCounter* _dbus_counter_new (void); DBusCounter* _dbus_counter_ref (DBusCounter *counter); void _dbus_counter_unref (DBusCounter *counter); void _dbus_counter_adjust_size (DBusCounter *counter, long delta); void _dbus_counter_adjust_unix_fd (DBusCounter *counter, long delta); void _dbus_counter_notify (DBusCounter *counter); long _dbus_counter_get_size_value (DBusCounter *counter); long _dbus_counter_get_unix_fd_value (DBusCounter *counter); void _dbus_counter_set_notify (DBusCounter *counter, long size_guard_value, long unix_fd_guard_value, DBusCounterNotifyFunction function, void *user_data); /* if DBUS_ENABLE_STATS */ long _dbus_counter_get_peak_size_value (DBusCounter *counter); long _dbus_counter_get_peak_unix_fd_value (DBusCounter *counter); DBUS_END_DECLS #endif /* DBUS_RESOURCES_H */ dbus-1.10.6/dbus/dbus-resources.c0000644000175000017500000002154412602773110016611 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-resources.c Resource tracking/limits * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include /** * @defgroup DBusResources Resource limits related code * @ingroup DBusInternals * @brief DBusCounter and other stuff related to resource limits * * Types and functions related to tracking resource limits, * such as the maximum amount of memory/unix fds a connection can use * for messages, etc. */ /** * @defgroup DBusResourcesInternals Resource limits implementation details * @ingroup DBusInternals * @brief Resource limits implementation details * * Implementation details of resource limits code. * * @{ */ /** * @brief Internals of DBusCounter. * * DBusCounter internals. DBusCounter is an opaque object, it must be * used via accessor functions. */ struct DBusCounter { int refcount; /**< reference count */ long size_value; /**< current size counter value */ long unix_fd_value; /**< current unix fd counter value */ #ifdef DBUS_ENABLE_STATS long peak_size_value; /**< largest ever size counter value */ long peak_unix_fd_value; /**< largest ever unix fd counter value */ #endif long notify_size_guard_value; /**< call notify function when crossing this size value */ long notify_unix_fd_guard_value; /**< call notify function when crossing this unix fd value */ DBusCounterNotifyFunction notify_function; /**< notify function */ void *notify_data; /**< data for notify function */ dbus_bool_t notify_pending : 1; /**< TRUE if the guard value has been crossed */ DBusRMutex *mutex; /**< Lock on the entire DBusCounter */ }; /** @} */ /* end of resource limits internals docs */ /** * @addtogroup DBusResources * @{ */ /** * Creates a new DBusCounter. DBusCounter is used * to count usage of some resource such as memory. * * @returns new counter or #NULL on failure */ DBusCounter* _dbus_counter_new (void) { DBusCounter *counter; counter = dbus_new0 (DBusCounter, 1); if (counter == NULL) return NULL; counter->refcount = 1; _dbus_rmutex_new_at_location (&counter->mutex); if (counter->mutex == NULL) { dbus_free (counter); counter = NULL; } return counter; } /** * Increments refcount of the counter * * @param counter the counter * @returns the counter */ DBusCounter * _dbus_counter_ref (DBusCounter *counter) { _dbus_rmutex_lock (counter->mutex); _dbus_assert (counter->refcount > 0); counter->refcount += 1; _dbus_rmutex_unlock (counter->mutex); return counter; } /** * Decrements refcount of the counter and possibly * finalizes the counter. * * @param counter the counter */ void _dbus_counter_unref (DBusCounter *counter) { dbus_bool_t last_ref = FALSE; _dbus_rmutex_lock (counter->mutex); _dbus_assert (counter->refcount > 0); counter->refcount -= 1; last_ref = (counter->refcount == 0); _dbus_rmutex_unlock (counter->mutex); if (last_ref) { _dbus_rmutex_free_at_location (&counter->mutex); dbus_free (counter); } } /** * Adjusts the value of the size counter by the given * delta which may be positive or negative. * * This function may be called with locks held. After calling it, when * any relevant locks are no longer held you must call _dbus_counter_notify(). * * @param counter the counter * @param delta value to add to the size counter's current value */ void _dbus_counter_adjust_size (DBusCounter *counter, long delta) { long old = 0; _dbus_rmutex_lock (counter->mutex); old = counter->size_value; counter->size_value += delta; #ifdef DBUS_ENABLE_STATS if (counter->peak_size_value < counter->size_value) counter->peak_size_value = counter->size_value; #endif #if 0 _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", old, delta, counter->size_value); #endif if (counter->notify_function != NULL && ((old < counter->notify_size_guard_value && counter->size_value >= counter->notify_size_guard_value) || (old >= counter->notify_size_guard_value && counter->size_value < counter->notify_size_guard_value))) counter->notify_pending = TRUE; _dbus_rmutex_unlock (counter->mutex); } /** * Calls the notify function from _dbus_counter_set_notify(), * if that function has been specified and the counter has crossed the * guard value (in either direction) since the last call to this function. * * This function must not be called with locks held, since it can call out * to user code. */ void _dbus_counter_notify (DBusCounter *counter) { DBusCounterNotifyFunction notify_function = NULL; void *notify_data = NULL; _dbus_rmutex_lock (counter->mutex); if (counter->notify_pending) { counter->notify_pending = FALSE; notify_function = counter->notify_function; notify_data = counter->notify_data; } _dbus_rmutex_unlock (counter->mutex); if (notify_function != NULL) (* notify_function) (counter, notify_data); } /** * Adjusts the value of the unix fd counter by the given * delta which may be positive or negative. * * This function may be called with locks held. After calling it, when * any relevant locks are no longer held you must call _dbus_counter_notify(). * * @param counter the counter * @param delta value to add to the unix fds counter's current value */ void _dbus_counter_adjust_unix_fd (DBusCounter *counter, long delta) { long old = 0; _dbus_rmutex_lock (counter->mutex); old = counter->unix_fd_value; counter->unix_fd_value += delta; #ifdef DBUS_ENABLE_STATS if (counter->peak_unix_fd_value < counter->unix_fd_value) counter->peak_unix_fd_value = counter->unix_fd_value; #endif #if 0 _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", old, delta, counter->unix_fd_value); #endif if (counter->notify_function != NULL && ((old < counter->notify_unix_fd_guard_value && counter->unix_fd_value >= counter->notify_unix_fd_guard_value) || (old >= counter->notify_unix_fd_guard_value && counter->unix_fd_value < counter->notify_unix_fd_guard_value))) counter->notify_pending = TRUE; _dbus_rmutex_unlock (counter->mutex); } /** * Gets the current value of the size counter. * * @param counter the counter * @returns its current size value */ long _dbus_counter_get_size_value (DBusCounter *counter) { return counter->size_value; } /** * Gets the current value of the unix fd counter. * * @param counter the counter * @returns its current unix fd value */ long _dbus_counter_get_unix_fd_value (DBusCounter *counter) { return counter->unix_fd_value; } /** * Sets the notify function for this counter; the notify function is * called whenever the counter's values cross the guard values in * either direction (moving up, or moving down). * * @param counter the counter * @param size_guard_value the value we're notified if the size counter crosses * @param unix_fd_guard_value the value we're notified if the unix fd counter crosses * @param function function to call in order to notify * @param user_data data to pass to the function */ void _dbus_counter_set_notify (DBusCounter *counter, long size_guard_value, long unix_fd_guard_value, DBusCounterNotifyFunction function, void *user_data) { _dbus_rmutex_lock (counter->mutex); counter->notify_size_guard_value = size_guard_value; counter->notify_unix_fd_guard_value = unix_fd_guard_value; counter->notify_function = function; counter->notify_data = user_data; counter->notify_pending = FALSE; _dbus_rmutex_unlock (counter->mutex); } #ifdef DBUS_ENABLE_STATS long _dbus_counter_get_peak_size_value (DBusCounter *counter) { return counter->peak_size_value; } long _dbus_counter_get_peak_unix_fd_value (DBusCounter *counter) { return counter->peak_unix_fd_value; } #endif /** @} */ /* end of resource limits exported API */ dbus-1.10.6/dbus/dbus-pending-call-internal.h0000644000175000017500000001000612602773110020742 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pending-call-internal.h DBusPendingCall internal interfaces * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_PENDING_CALL_INTERNAL_H #define DBUS_PENDING_CALL_INTERNAL_H #include #include #include #include DBUS_BEGIN_DECLS dbus_bool_t _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending); void _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, dbus_bool_t is_added); DBusTimeout * _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending); dbus_uint32_t _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending); void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, dbus_uint32_t serial); DBusConnection * _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending); DBusConnection * _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending); dbus_bool_t _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending); void _dbus_pending_call_complete (DBusPendingCall *pending); void _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, DBusMessage *message); void _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, DBusConnection *connection); void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, dbus_uint32_t serial); dbus_bool_t _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, DBusMessage *message, dbus_uint32_t serial); DBUS_PRIVATE_EXPORT DBusPendingCall* _dbus_pending_call_new_unlocked (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler); DBUS_PRIVATE_EXPORT DBusPendingCall* _dbus_pending_call_ref_unlocked (DBusPendingCall *pending); DBUS_PRIVATE_EXPORT void _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending); dbus_bool_t _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func); DBUS_END_DECLS #endif /* DBUS_PENDING_CALL_INTERNAL_H */ dbus-1.10.6/dbus/dbus-pending-call.c0000644000175000017500000005725012602773110017137 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pending-call.c Object representing a call in progress. * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-message-internal.h" #include "dbus-pending-call-internal.h" #include "dbus-pending-call.h" #include "dbus-list.h" #include "dbus-threads.h" #include "dbus-test.h" /** * @defgroup DBusPendingCallInternals DBusPendingCall implementation details * @ingroup DBusInternals * @brief DBusPendingCall private implementation details. * * The guts of DBusPendingCall and its methods. * * @{ */ /** * @brief Internals of DBusPendingCall * * Opaque object representing a reply message that we're waiting for. */ /** * shorter and more visible way to write _dbus_connection_lock() */ #define CONNECTION_LOCK(connection) _dbus_connection_lock(connection) /** * shorter and more visible way to write _dbus_connection_unlock() */ #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection) /** * Implementation details of #DBusPendingCall - all fields are private. */ struct DBusPendingCall { DBusAtomic refcount; /**< reference count */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ DBusConnection *connection; /**< Connections we're associated with */ DBusMessage *reply; /**< Reply (after we've received it) */ DBusTimeout *timeout; /**< Timeout */ DBusList *timeout_link; /**< Preallocated timeout response */ dbus_uint32_t reply_serial; /**< Expected serial of reply */ unsigned int completed : 1; /**< TRUE if completed */ unsigned int timeout_added : 1; /**< Have added the timeout */ }; static void _dbus_pending_call_trace_ref (DBusPendingCall *pending_call, int old_refcount, int new_refcount, const char *why) { #ifdef DBUS_ENABLE_VERBOSE_MODE static int enabled = -1; _dbus_trace_ref ("DBusPendingCall", pending_call, old_refcount, new_refcount, why, "DBUS_PENDING_CALL_TRACE", &enabled); #endif } static dbus_int32_t notify_user_data_slot = -1; /** * Creates a new pending reply object. * * @param connection connection where reply will arrive * @param timeout_milliseconds length of timeout, -1 (or * #DBUS_TIMEOUT_USE_DEFAULT) for default, * #DBUS_TIMEOUT_INFINITE for no timeout * @param timeout_handler timeout handler, takes pending call as data * @returns a new #DBusPendingCall or #NULL if no memory. */ DBusPendingCall* _dbus_pending_call_new_unlocked (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler) { DBusPendingCall *pending; DBusTimeout *timeout; _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1); if (timeout_milliseconds == -1) timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) return NULL; pending = dbus_new0 (DBusPendingCall, 1); if (pending == NULL) { dbus_pending_call_free_data_slot (¬ify_user_data_slot); return NULL; } if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE) { timeout = _dbus_timeout_new (timeout_milliseconds, timeout_handler, pending, NULL); if (timeout == NULL) { dbus_pending_call_free_data_slot (¬ify_user_data_slot); dbus_free (pending); return NULL; } pending->timeout = timeout; } else { pending->timeout = NULL; } _dbus_atomic_inc (&pending->refcount); pending->connection = connection; _dbus_connection_ref_unlocked (pending->connection); _dbus_data_slot_list_init (&pending->slot_list); _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked"); return pending; } /** * Sets the reply of a pending call with the given message, * or if the message is #NULL, by timing out the pending call. * * @param pending the pending call * @param message the message to complete the call with, or #NULL * to time out the call */ void _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, DBusMessage *message) { if (message == NULL) { message = pending->timeout_link->data; _dbus_list_clear (&pending->timeout_link); } else dbus_message_ref (message); _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", message, dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? "method return" : dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : "other type", pending->reply_serial); _dbus_assert (pending->reply == NULL); _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); pending->reply = message; } /** * Calls notifier function for the pending call * and sets the call to completed. * * @param pending the pending call * */ void _dbus_pending_call_complete (DBusPendingCall *pending) { _dbus_assert (!pending->completed); pending->completed = TRUE; if (pending->function) { void *user_data; user_data = dbus_pending_call_get_data (pending, notify_user_data_slot); (* pending->function) (pending, user_data); } } /** * If the pending call hasn't been timed out, add its timeout * error reply to the connection's incoming message queue. * * @param pending the pending call * @param connection the connection the call was sent to */ void _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, DBusConnection *connection) { _dbus_assert (connection == pending->connection); if (pending->timeout_link) { _dbus_connection_queue_synthesized_message_link (connection, pending->timeout_link); pending->timeout_link = NULL; } } /** * Checks to see if a timeout has been added * * @param pending the pending_call * @returns #TRUE if there is a timeout or #FALSE if not */ dbus_bool_t _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending) { _dbus_assert (pending != NULL); return pending->timeout_added; } /** * Sets wether the timeout has been added * * @param pending the pending_call * @param is_added whether or not a timeout is added */ void _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, dbus_bool_t is_added) { _dbus_assert (pending != NULL); pending->timeout_added = is_added; } /** * Retrives the timeout * * @param pending the pending_call * @returns a timeout object or NULL if call has no timeout */ DBusTimeout * _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending) { _dbus_assert (pending != NULL); return pending->timeout; } /** * Gets the reply's serial number * * @param pending the pending_call * @returns a serial number for the reply or 0 */ dbus_uint32_t _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending) { _dbus_assert (pending != NULL); return pending->reply_serial; } /** * Sets the reply's serial number * * @param pending the pending_call * @param serial the serial number */ void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, dbus_uint32_t serial) { _dbus_assert (pending != NULL); _dbus_assert (pending->reply_serial == 0); pending->reply_serial = serial; } /** * Gets the connection associated with this pending call. * * @param pending the pending_call * @returns the connection associated with the pending call */ DBusConnection * _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending) { _dbus_assert (pending != NULL); CONNECTION_LOCK (pending->connection); return pending->connection; } /** * Gets the connection associated with this pending call. * * @param pending the pending_call * @returns the connection associated with the pending call */ DBusConnection * _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending) { _dbus_assert (pending != NULL); return pending->connection; } /** * Sets the reply message associated with the pending call to a timeout error * * @param pending the pending_call * @param message the message we are sending the error reply to * @param serial serial number for the reply * @return #FALSE on OOM */ dbus_bool_t _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, DBusMessage *message, dbus_uint32_t serial) { DBusList *reply_link; DBusMessage *reply; reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, "Did not receive a reply. Possible causes include: " "the remote application did not send a reply, " "the message bus security policy blocked the reply, " "the reply timeout expired, or " "the network connection was broken."); if (reply == NULL) return FALSE; reply_link = _dbus_list_alloc_link (reply); if (reply_link == NULL) { /* it's OK to unref this, nothing that could have attached a callback * has ever seen it */ dbus_message_unref (reply); return FALSE; } pending->timeout_link = reply_link; _dbus_pending_call_set_reply_serial_unlocked (pending, serial); return TRUE; } /** * Increments the reference count on a pending call, * while the lock on its connection is already held. * * @param pending the pending call object * @returns the pending call object */ DBusPendingCall * _dbus_pending_call_ref_unlocked (DBusPendingCall *pending) { dbus_int32_t old_refcount; old_refcount = _dbus_atomic_inc (&pending->refcount); _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1, "ref_unlocked"); return pending; } static void _dbus_pending_call_last_unref (DBusPendingCall *pending) { DBusConnection *connection; /* If we get here, we should be already detached * from the connection, or never attached. */ _dbus_assert (!pending->timeout_added); connection = pending->connection; /* this assumes we aren't holding connection lock... */ _dbus_data_slot_list_free (&pending->slot_list); if (pending->timeout != NULL) _dbus_timeout_unref (pending->timeout); if (pending->timeout_link) { dbus_message_unref ((DBusMessage *)pending->timeout_link->data); _dbus_list_free_link (pending->timeout_link); pending->timeout_link = NULL; } if (pending->reply) { dbus_message_unref (pending->reply); pending->reply = NULL; } dbus_free (pending); dbus_pending_call_free_data_slot (¬ify_user_data_slot); /* connection lock should not be held. */ /* Free the connection last to avoid a weird state while * calling out to application code where the pending exists * but not the connection. */ dbus_connection_unref (connection); } /** * Decrements the reference count on a pending call, * freeing it if the count reaches 0. Assumes * connection lock is already held. * * @param pending the pending call object */ void _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) { dbus_int32_t old_refcount; old_refcount = _dbus_atomic_dec (&pending->refcount); _dbus_assert (old_refcount > 0); _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1, "unref_and_unlock"); CONNECTION_UNLOCK (pending->connection); if (old_refcount == 1) _dbus_pending_call_last_unref (pending); } /** * Checks whether the pending call has received a reply * yet, or not. Assumes connection lock is held. * * @param pending the pending call * @returns #TRUE if a reply has been received */ dbus_bool_t _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) { return pending->completed; } static DBusDataSlotAllocator slot_allocator = _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (pending_call_slots)); /** * Stores a pointer on a #DBusPendingCall, along * with an optional function to be used for freeing * the data when the data is set again, or when * the pending call is finalized. The slot number * must have been allocated with dbus_pending_call_allocate_data_slot(). * * @param pending the pending_call * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func) { DBusFreeFunction old_free_func; void *old_data; dbus_bool_t retval; retval = _dbus_data_slot_list_set (&slot_allocator, &pending->slot_list, slot, data, free_data_func, &old_free_func, &old_data); /* Drop locks to call out to app code */ CONNECTION_UNLOCK (pending->connection); if (retval) { if (old_free_func) (* old_free_func) (old_data); } CONNECTION_LOCK (pending->connection); return retval; } /** @} */ /** * @defgroup DBusPendingCall DBusPendingCall * @ingroup DBus * @brief Pending reply to a method call message * * A DBusPendingCall is an object representing an * expected reply. A #DBusPendingCall can be created * when you send a message that should have a reply. * * @{ */ /** * @def DBUS_TIMEOUT_INFINITE * * An integer constant representing an infinite timeout. This has the * numeric value 0x7fffffff (the largest 32-bit signed integer). * * For source compatibility with D-Bus versions earlier than 1.4.12, use * 0x7fffffff, or INT32_MAX (assuming your platform has it). */ /** * @def DBUS_TIMEOUT_USE_DEFAULT * * An integer constant representing a request to use the default timeout. * This has numeric value -1. * * For source compatibility with D-Bus versions earlier than 1.4.12, use a * literal -1. */ /** * @typedef DBusPendingCall * * Opaque data type representing a message pending. */ /** * Increments the reference count on a pending call. * * @param pending the pending call object * @returns the pending call object */ DBusPendingCall * dbus_pending_call_ref (DBusPendingCall *pending) { dbus_int32_t old_refcount; _dbus_return_val_if_fail (pending != NULL, NULL); old_refcount = _dbus_atomic_inc (&pending->refcount); _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1, "ref"); return pending; } /** * Decrements the reference count on a pending call, * freeing it if the count reaches 0. * * @param pending the pending call object */ void dbus_pending_call_unref (DBusPendingCall *pending) { dbus_int32_t old_refcount; _dbus_return_if_fail (pending != NULL); old_refcount = _dbus_atomic_dec (&pending->refcount); _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1, "unref"); if (old_refcount == 1) _dbus_pending_call_last_unref(pending); } /** * Sets a notification function to be called when the reply is * received or the pending call times out. * * @param pending the pending call * @param function notifier function * @param user_data data to pass to notifier function * @param free_user_data function to free the user data * @returns #FALSE if not enough memory */ dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data) { dbus_bool_t ret = FALSE; _dbus_return_val_if_fail (pending != NULL, FALSE); CONNECTION_LOCK (pending->connection); /* could invoke application code! */ if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, user_data, free_user_data)) goto out; pending->function = function; ret = TRUE; out: CONNECTION_UNLOCK (pending->connection); return ret; } /** * Cancels the pending call, such that any reply or error received * will just be ignored. Drops the dbus library's internal reference * to the #DBusPendingCall so will free the call if nobody else is * holding a reference. However you usually get a reference from * dbus_connection_send_with_reply() so probably your app owns a ref * also. * * Note that canceling a pending call will not simulate a * timed-out call; if a call times out, then a timeout error reply is * received. If you cancel the call, no reply is received unless the * the reply was already received before you canceled. * * @param pending the pending call */ void dbus_pending_call_cancel (DBusPendingCall *pending) { _dbus_return_if_fail (pending != NULL); _dbus_connection_remove_pending_call (pending->connection, pending); } /** * Checks whether the pending call has received a reply * yet, or not. * * @param pending the pending call * @returns #TRUE if a reply has been received */ dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending) { dbus_bool_t completed; _dbus_return_val_if_fail (pending != NULL, FALSE); CONNECTION_LOCK (pending->connection); completed = pending->completed; CONNECTION_UNLOCK (pending->connection); return completed; } /** * Gets the reply, or returns #NULL if none has been received * yet. Ownership of the reply message passes to the caller. This * function can only be called once per pending call, since the reply * message is tranferred to the caller. * * @param pending the pending call * @returns the reply message or #NULL. */ DBusMessage* dbus_pending_call_steal_reply (DBusPendingCall *pending) { DBusMessage *message; _dbus_return_val_if_fail (pending != NULL, NULL); _dbus_return_val_if_fail (pending->completed, NULL); _dbus_return_val_if_fail (pending->reply != NULL, NULL); CONNECTION_LOCK (pending->connection); message = pending->reply; pending->reply = NULL; CONNECTION_UNLOCK (pending->connection); _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply"); return message; } /** * Block until the pending call is completed. The blocking is as with * dbus_connection_send_with_reply_and_block(); it does not enter the * main loop or process other messages, it simply waits for the reply * in question. * * If the pending call is already completed, this function returns * immediately. * * @todo when you start blocking, the timeout is reset, but it should * really only use time remaining since the pending call was created. * This requires storing timestamps instead of intervals in the timeout * * @param pending the pending call */ void dbus_pending_call_block (DBusPendingCall *pending) { _dbus_return_if_fail (pending != NULL); _dbus_connection_block_pending_call (pending); } /** * Allocates an integer ID to be used for storing application-specific * data on any DBusPendingCall. The allocated ID may then be used * with dbus_pending_call_set_data() and dbus_pending_call_get_data(). * The passed-in slot must be initialized to -1, and is filled in * with the slot ID. If the passed-in slot is not -1, it's assumed * to be already allocated, and its refcount is incremented. * * The allocated slot is global, i.e. all DBusPendingCall objects will * have a slot with the given integer ID reserved. * * @param slot_p address of a global variable storing the slot * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) { _dbus_return_val_if_fail (slot_p != NULL, FALSE); return _dbus_data_slot_allocator_alloc (&slot_allocator, slot_p); } /** * Deallocates a global ID for #DBusPendingCall data slots. * dbus_pending_call_get_data() and dbus_pending_call_set_data() may * no longer be used with this slot. Existing data stored on existing * DBusPendingCall objects will be freed when the #DBusPendingCall is * finalized, but may not be retrieved (and may only be replaced if * someone else reallocates the slot). When the refcount on the * passed-in slot reaches 0, it is set to -1. * * @param slot_p address storing the slot to deallocate */ void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) { _dbus_return_if_fail (slot_p != NULL); _dbus_return_if_fail (*slot_p >= 0); _dbus_data_slot_allocator_free (&slot_allocator, slot_p); } /** * Stores a pointer on a #DBusPendingCall, along * with an optional function to be used for freeing * the data when the data is set again, or when * the pending call is finalized. The slot number * must have been allocated with dbus_pending_call_allocate_data_slot(). * * @param pending the pending_call * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func) { dbus_bool_t retval; _dbus_return_val_if_fail (pending != NULL, FALSE); _dbus_return_val_if_fail (slot >= 0, FALSE); CONNECTION_LOCK (pending->connection); retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); CONNECTION_UNLOCK (pending->connection); return retval; } /** * Retrieves data previously set with dbus_pending_call_set_data(). * The slot must still be allocated (must not have been freed). * * @param pending the pending_call * @param slot the slot to get data from * @returns the data, or #NULL if not found */ void* dbus_pending_call_get_data (DBusPendingCall *pending, dbus_int32_t slot) { void *res; _dbus_return_val_if_fail (pending != NULL, NULL); CONNECTION_LOCK (pending->connection); res = _dbus_data_slot_list_get (&slot_allocator, &pending->slot_list, slot); CONNECTION_UNLOCK (pending->connection); return res; } /** @} */ dbus-1.10.6/dbus/dbus-object-tree.h0000644000175000017500000000620412602773110017003 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-object-tree.h DBusObjectTree (internals of DBusConnection) * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_OBJECT_TREE_H #define DBUS_OBJECT_TREE_H #include DBUS_BEGIN_DECLS typedef struct DBusObjectTree DBusObjectTree; DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection); DBusObjectTree* _dbus_object_tree_ref (DBusObjectTree *tree); void _dbus_object_tree_unref (DBusObjectTree *tree); dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error); void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, const char **path); DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusMessage *message, dbus_bool_t *found_object); void* _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, const char **path); void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree); dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, const char **parent_path, char ***child_entries); dbus_bool_t _dbus_decompose_path (const char *data, int len, char ***path, int *path_len); DBUS_END_DECLS #endif /* DBUS_OBJECT_TREE_H */ dbus-1.10.6/dbus/dbus-object-tree.c0000644000175000017500000021667512602773110017015 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) * * Copyright (C) 2003, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-object-tree.h" #include "dbus-connection-internal.h" #include "dbus-internals.h" #include "dbus-hash.h" #include "dbus-protocol.h" #include "dbus-string.h" #include #include /** * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship * @ingroup DBusInternals * @brief DBusObjectTree is used by DBusConnection to track the object tree * * Types and functions related to DBusObjectTree. These * are all library-internal. * * @{ */ /** Subnode of the object hierarchy */ typedef struct DBusObjectSubtree DBusObjectSubtree; static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, const DBusObjectPathVTable *vtable, void *user_data); static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); /** * Internals of DBusObjectTree */ struct DBusObjectTree { int refcount; /**< Reference count */ DBusConnection *connection; /**< Connection this tree belongs to */ DBusObjectSubtree *root; /**< Root of the tree ("/" node) */ }; /** * Struct representing a single registered subtree handler, or node * that's a parent of a registered subtree handler. If * message_function != NULL there's actually a handler at this node. */ struct DBusObjectSubtree { DBusAtomic refcount; /**< Reference count */ DBusObjectSubtree *parent; /**< Parent node */ DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */ DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ void *user_data; /**< Data for functions */ DBusObjectSubtree **subtrees; /**< Child nodes */ int n_subtrees; /**< Number of child nodes */ int max_subtrees; /**< Number of allocated entries in subtrees */ unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */ char name[1]; /**< Allocated as large as necessary */ }; /** * Creates a new object tree, representing a mapping from paths * to handler vtables. * * @param connection the connection this tree belongs to * @returns the new tree or #NULL if no memory */ DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection) { DBusObjectTree *tree; /* the connection passed in here isn't fully constructed, * so don't do anything more than store a pointer to * it */ tree = dbus_new0 (DBusObjectTree, 1); if (tree == NULL) goto oom; tree->refcount = 1; tree->connection = connection; tree->root = _dbus_object_subtree_new ("/", NULL, NULL); if (tree->root == NULL) goto oom; tree->root->invoke_as_fallback = TRUE; return tree; oom: if (tree) { dbus_free (tree); } return NULL; } /** * Increment the reference count * @param tree the object tree * @returns the object tree */ DBusObjectTree * _dbus_object_tree_ref (DBusObjectTree *tree) { _dbus_assert (tree->refcount > 0); tree->refcount += 1; return tree; } /** * Decrement the reference count * @param tree the object tree */ void _dbus_object_tree_unref (DBusObjectTree *tree) { _dbus_assert (tree->refcount > 0); tree->refcount -= 1; if (tree->refcount == 0) { _dbus_object_tree_free_all_unlocked (tree); dbus_free (tree); } } /** Set to 1 to get a bunch of debug spew about finding the * subtree nodes */ #define VERBOSE_FIND 0 static DBusObjectSubtree* find_subtree_recurse (DBusObjectSubtree *subtree, const char **path, dbus_bool_t create_if_not_found, int *index_in_parent, dbus_bool_t *exact_match) { int i, j; dbus_bool_t return_deepest_match; return_deepest_match = exact_match != NULL; _dbus_assert (!(return_deepest_match && create_if_not_found)); if (path[0] == NULL) { #if VERBOSE_FIND _dbus_verbose (" path exhausted, returning %s\n", subtree->name); #endif if (exact_match != NULL) *exact_match = TRUE; return subtree; } #if VERBOSE_FIND _dbus_verbose (" searching children of %s for %s\n", subtree->name, path[0]); #endif i = 0; j = subtree->n_subtrees; while (i < j) { int k, v; k = (i + j) / 2; v = strcmp (path[0], subtree->subtrees[k]->name); #if VERBOSE_FIND _dbus_verbose (" %s cmp %s = %d\n", path[0], subtree->subtrees[k]->name, v); #endif if (v == 0) { if (index_in_parent) { #if VERBOSE_FIND _dbus_verbose (" storing parent index %d\n", k); #endif *index_in_parent = k; } if (return_deepest_match) { DBusObjectSubtree *next; next = find_subtree_recurse (subtree->subtrees[k], &path[1], create_if_not_found, index_in_parent, exact_match); if (next == NULL && subtree->invoke_as_fallback) { #if VERBOSE_FIND _dbus_verbose (" no deeper match found, returning %s\n", subtree->name); #endif if (exact_match != NULL) *exact_match = FALSE; return subtree; } else return next; } else return find_subtree_recurse (subtree->subtrees[k], &path[1], create_if_not_found, index_in_parent, exact_match); } else if (v < 0) { j = k; } else { i = k + 1; } } #if VERBOSE_FIND _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", subtree->name, create_if_not_found); #endif if (create_if_not_found) { DBusObjectSubtree* child; int child_pos, new_n_subtrees; #if VERBOSE_FIND _dbus_verbose (" creating subtree %s\n", path[0]); #endif child = _dbus_object_subtree_new (path[0], NULL, NULL); if (child == NULL) return NULL; new_n_subtrees = subtree->n_subtrees + 1; if (new_n_subtrees > subtree->max_subtrees) { int new_max_subtrees; DBusObjectSubtree **new_subtrees; new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; new_subtrees = dbus_realloc (subtree->subtrees, new_max_subtrees * sizeof (DBusObjectSubtree*)); if (new_subtrees == NULL) { _dbus_object_subtree_unref (child); return NULL; } subtree->subtrees = new_subtrees; subtree->max_subtrees = new_max_subtrees; } /* The binary search failed, so i == j points to the place the child should be inserted. */ child_pos = i; _dbus_assert (child_pos < new_n_subtrees && new_n_subtrees <= subtree->max_subtrees); if (child_pos + 1 < new_n_subtrees) { memmove (&subtree->subtrees[child_pos+1], &subtree->subtrees[child_pos], (new_n_subtrees - child_pos - 1) * sizeof subtree->subtrees[0]); } subtree->subtrees[child_pos] = child; if (index_in_parent) *index_in_parent = child_pos; subtree->n_subtrees = new_n_subtrees; child->parent = subtree; return find_subtree_recurse (child, &path[1], create_if_not_found, index_in_parent, exact_match); } else { if (exact_match != NULL) *exact_match = FALSE; return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; } } #ifdef DBUS_ENABLE_EMBEDDED_TESTS static DBusObjectSubtree* find_subtree (DBusObjectTree *tree, const char **path, int *index_in_parent) { DBusObjectSubtree *subtree; #if VERBOSE_FIND _dbus_verbose ("Looking for exact registered subtree\n"); #endif subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); if (subtree && subtree->message_function == NULL) return NULL; else return subtree; } #endif static DBusObjectSubtree* lookup_subtree (DBusObjectTree *tree, const char **path) { #if VERBOSE_FIND _dbus_verbose ("Looking for subtree\n"); #endif return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); } static DBusObjectSubtree* find_handler (DBusObjectTree *tree, const char **path, dbus_bool_t *exact_match) { #if VERBOSE_FIND _dbus_verbose ("Looking for deepest handler\n"); #endif _dbus_assert (exact_match != NULL); *exact_match = FALSE; /* ensure always initialized */ return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); } static DBusObjectSubtree* ensure_subtree (DBusObjectTree *tree, const char **path) { #if VERBOSE_FIND _dbus_verbose ("Ensuring subtree\n"); #endif return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); } static char *flatten_path (const char **path); /** * Registers a new subtree in the global object tree. * * @param tree the global object tree * @param fallback #TRUE to handle messages to children of this path * @param path NULL-terminated array of path elements giving path to subtree * @param vtable the vtable used to traverse this subtree * @param user_data user data to pass to methods in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error) { DBusObjectSubtree *subtree; _dbus_assert (tree != NULL); _dbus_assert (vtable->message_function != NULL); _dbus_assert (path != NULL); subtree = ensure_subtree (tree, path); if (subtree == NULL) { _DBUS_SET_OOM (error); return FALSE; } if (subtree->message_function != NULL) { if (error != NULL) { char *complete_path = flatten_path (path); dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE, "A handler is already registered for %s", complete_path ? complete_path : "(cannot represent path: out of memory!)"); dbus_free (complete_path); } return FALSE; } subtree->message_function = vtable->message_function; subtree->unregister_function = vtable->unregister_function; subtree->user_data = user_data; subtree->invoke_as_fallback = fallback != FALSE; return TRUE; } /** * Attempts to unregister the given subtree. If the subtree is registered, * stores its unregister function and user data for later use and returns * #TRUE. If subtree is not registered, simply returns #FALSE. Does not free * subtree or remove it from the object tree. * * @param subtree the subtree to unregister * @param unregister_function_out stores subtree's unregister_function * @param user_data_out stores subtree's user_data * @return #FALSE if the subtree was not registered, #TRUE on success */ static dbus_bool_t unregister_subtree (DBusObjectSubtree *subtree, DBusObjectPathUnregisterFunction *unregister_function_out, void **user_data_out) { _dbus_assert (subtree != NULL); _dbus_assert (unregister_function_out != NULL); _dbus_assert (user_data_out != NULL); /* Confirm subtree is registered */ if (subtree->message_function != NULL) { subtree->message_function = NULL; *unregister_function_out = subtree->unregister_function; *user_data_out = subtree->user_data; subtree->unregister_function = NULL; subtree->user_data = NULL; return TRUE; } else { /* Assert that this unregistered subtree is either the root node or has children, otherwise we have a dangling path which should never happen */ _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0); /* The subtree is not registered */ return FALSE; } } /** * Attempts to remove a child subtree from its parent. If removal is * successful, also frees the child. Returns #TRUE on success, #FALSE * otherwise. A #FALSE return value tells unregister_and_free_path_recurse to * stop attempting to remove ancestors, i.e., that no ancestors of the * specified child are eligible for removal. * * @param parent parent from which to remove child * @param child_index parent->subtrees index of child to remove * @return #TRUE if removal and free succeed, #FALSE otherwise */ static dbus_bool_t attempt_child_removal (DBusObjectSubtree *parent, int child_index) { /* Candidate for removal */ DBusObjectSubtree* candidate; _dbus_assert (parent != NULL); _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees); candidate = parent->subtrees[child_index]; _dbus_assert (candidate != NULL); if (candidate->n_subtrees == 0 && candidate->message_function == NULL) { /* The candidate node is childless and is not a registered path, so... */ /* ... remove it from its parent... */ /* Assumes a 0-byte memmove is OK */ memmove (&parent->subtrees[child_index], &parent->subtrees[child_index + 1], (parent->n_subtrees - child_index - 1) * sizeof (parent->subtrees[0])); parent->n_subtrees -= 1; /* ... and free it */ candidate->parent = NULL; _dbus_object_subtree_unref (candidate); return TRUE; } return FALSE; } /** * Searches the object tree for a registered subtree node at the given path. * If a registered node is found, it is removed from the tree and freed, and * TRUE is returned. If a registered subtree node is not found at the given * path, the tree is not modified and FALSE is returned. * * The found node's unregister_function and user_data are returned in the * corresponding _out arguments. The caller should define these variables and * pass their addresses as arguments. * * Likewise, the caller should define and set to TRUE a boolean variable, then * pass its address as the continue_removal_attempts argument. * * Once a matching registered node is found, removed and freed, the recursive * return path is traversed. Along the way, eligible ancestor nodes are * removed and freed. An ancestor node is eligible for removal if and only if * 1) it has no children, i.e., it has become childless and 2) it is not itself * a registered handler. * * For example, suppose /A/B and /A/C are registered paths, and that these are * the only paths in the tree. If B is removed and freed, C is still reachable * through A, so A cannot be removed and freed. If C is subsequently removed * and freed, then A becomes a childless node and it becomes eligible for * removal, and will be removed and freed. * * Similarly, suppose /A is a registered path, and /A/B is also a registered * path, and that these are the only paths in the tree. If B is removed and * freed, then even though A has become childless, it can't be freed because it * refers to a path that is still registered. * * @param subtree subtree from which to start the search, root for initial call * @param path path to subtree (same as _dbus_object_tree_unregister_and_unlock) * @param continue_removal_attempts pointer to a bool, #TRUE for initial call * @param unregister_function_out returns the found node's unregister_function * @param user_data_out returns the found node's user_data * @returns #TRUE if a registered node was found at path, #FALSE otherwise */ static dbus_bool_t unregister_and_free_path_recurse (DBusObjectSubtree *subtree, const char **path, dbus_bool_t *continue_removal_attempts, DBusObjectPathUnregisterFunction *unregister_function_out, void **user_data_out) { int i, j; _dbus_assert (continue_removal_attempts != NULL); _dbus_assert (*continue_removal_attempts); _dbus_assert (unregister_function_out != NULL); _dbus_assert (user_data_out != NULL); if (path[0] == NULL) return unregister_subtree (subtree, unregister_function_out, user_data_out); i = 0; j = subtree->n_subtrees; while (i < j) { int k, v; k = (i + j) / 2; v = strcmp (path[0], subtree->subtrees[k]->name); if (v == 0) { dbus_bool_t freed; freed = unregister_and_free_path_recurse (subtree->subtrees[k], &path[1], continue_removal_attempts, unregister_function_out, user_data_out); if (freed && *continue_removal_attempts) *continue_removal_attempts = attempt_child_removal (subtree, k); return freed; } else if (v < 0) { j = k; } else { i = k + 1; } } return FALSE; } /** * Unregisters an object subtree that was registered with the * same path. * * @param tree the global object tree * @param path path to the subtree (same as the one passed to _dbus_object_tree_register()) */ void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, const char **path) { dbus_bool_t found_subtree; dbus_bool_t continue_removal_attempts; DBusObjectPathUnregisterFunction unregister_function; void *user_data; DBusConnection *connection; _dbus_assert (tree != NULL); _dbus_assert (path != NULL); continue_removal_attempts = TRUE; unregister_function = NULL; user_data = NULL; found_subtree = unregister_and_free_path_recurse (tree->root, path, &continue_removal_attempts, &unregister_function, &user_data); #ifndef DBUS_DISABLE_CHECKS if (found_subtree == FALSE) { _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", path[0] ? path[0] : "null", (path[0] && path[1]) ? path[1] : "null"); goto unlock; } #else _dbus_assert (found_subtree == TRUE); #endif unlock: connection = tree->connection; /* Unlock and call application code */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (connection) #endif { _dbus_connection_ref_unlocked (connection); _dbus_verbose ("unlock\n"); _dbus_connection_unlock (connection); } if (unregister_function) (* unregister_function) (connection, user_data); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (connection) #endif dbus_connection_unref (connection); } static void free_subtree_recurse (DBusConnection *connection, DBusObjectSubtree *subtree) { /* Delete them from the end, for slightly * more robustness against odd reentrancy. */ while (subtree->n_subtrees > 0) { DBusObjectSubtree *child; child = subtree->subtrees[subtree->n_subtrees - 1]; subtree->subtrees[subtree->n_subtrees - 1] = NULL; subtree->n_subtrees -= 1; child->parent = NULL; free_subtree_recurse (connection, child); } /* Call application code */ if (subtree->unregister_function) (* subtree->unregister_function) (connection, subtree->user_data); subtree->message_function = NULL; subtree->unregister_function = NULL; subtree->user_data = NULL; /* Now free ourselves */ _dbus_object_subtree_unref (subtree); } /** * Free all the handlers in the tree. Lock on tree's connection * must not be held. * * @param tree the object tree */ void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) { if (tree->root) free_subtree_recurse (tree->connection, tree->root); tree->root = NULL; } static dbus_bool_t _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, const char **parent_path, char ***child_entries) { DBusObjectSubtree *subtree; char **retval; _dbus_assert (parent_path != NULL); _dbus_assert (child_entries != NULL); *child_entries = NULL; subtree = lookup_subtree (tree, parent_path); if (subtree == NULL) { retval = dbus_new0 (char *, 1); } else { int i; retval = dbus_new0 (char*, subtree->n_subtrees + 1); if (retval == NULL) goto out; i = 0; while (i < subtree->n_subtrees) { retval[i] = _dbus_strdup (subtree->subtrees[i]->name); if (retval[i] == NULL) { dbus_free_string_array (retval); retval = NULL; goto out; } ++i; } } out: *child_entries = retval; return retval != NULL; } static DBusHandlerResult handle_default_introspect_and_unlock (DBusObjectTree *tree, DBusMessage *message, const char **path) { DBusString xml; DBusHandlerResult result; char **children; int i; DBusMessage *reply; DBusMessageIter iter; const char *v_STRING; dbus_bool_t already_unlocked; /* We have the connection lock here */ already_unlocked = FALSE; _dbus_verbose (" considering default Introspect() handler...\n"); reply = NULL; if (!dbus_message_is_method_call (message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } _dbus_verbose (" using default Introspect() handler!\n"); if (!_dbus_string_init (&xml)) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } return DBUS_HANDLER_RESULT_NEED_MEMORY; } result = DBUS_HANDLER_RESULT_NEED_MEMORY; children = NULL; if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) goto out; if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) goto out; if (!_dbus_string_append (&xml, "\n")) goto out; i = 0; while (children[i] != NULL) { if (!_dbus_string_append_printf (&xml, " \n", children[i])) goto out; ++i; } if (!_dbus_string_append (&xml, "\n")) goto out; reply = dbus_message_new_method_return (message); if (reply == NULL) goto out; dbus_message_iter_init_append (reply, &iter); v_STRING = _dbus_string_get_const_data (&xml); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) goto out; #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { already_unlocked = TRUE; if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) goto out; } result = DBUS_HANDLER_RESULT_HANDLED; out: #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { if (!already_unlocked) { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } } _dbus_string_free (&xml); dbus_free_string_array (children); if (reply) dbus_message_unref (reply); return result; } /** * Tries to dispatch a message by directing it to handler for the * object path listed in the message header, if any. Messages are * dispatched first to the registered handler that matches the largest * number of path elements; that is, message to /foo/bar/baz would go * to the handler for /foo/bar before the one for /foo. * * @todo thread problems * * @param tree the global object tree * @param message the message to dispatch * @param found_object return location for the object * @returns whether message was handled successfully */ DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusMessage *message, dbus_bool_t *found_object) { char **path; dbus_bool_t exact_match; DBusList *list; DBusList *link; DBusHandlerResult result; DBusObjectSubtree *subtree; #if 0 _dbus_verbose ("Dispatch of message by object path\n"); #endif path = NULL; if (!dbus_message_get_path_decomposed (message, &path)) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } _dbus_verbose ("No memory to get decomposed path\n"); return DBUS_HANDLER_RESULT_NEED_MEMORY; } if (path == NULL) { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } _dbus_verbose ("No path field in message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* Find the deepest path that covers the path in the message */ subtree = find_handler (tree, (const char**) path, &exact_match); if (found_object) *found_object = !!subtree; /* Build a list of all paths that cover the path in the message */ list = NULL; while (subtree != NULL) { if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) { _dbus_object_subtree_ref (subtree); /* run deepest paths first */ if (!_dbus_list_append (&list, subtree)) { result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_object_subtree_unref (subtree); goto free_and_return; } } exact_match = FALSE; subtree = subtree->parent; } _dbus_verbose ("%d handlers in the path tree for this message\n", _dbus_list_get_length (&list)); /* Invoke each handler in the list */ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; link = _dbus_list_get_first_link (&list); while (link != NULL) { DBusList *next = _dbus_list_get_next_link (&list, link); subtree = link->data; /* message_function is NULL if we're unregistered * due to reentrancy */ if (subtree->message_function) { DBusObjectPathMessageFunction message_function; void *user_data; message_function = subtree->message_function; user_data = subtree->user_data; #if 0 _dbus_verbose (" (invoking a handler)\n"); #endif #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } /* FIXME you could unregister the subtree in another thread * before we invoke the callback, and I can't figure out a * good way to solve this. */ result = (* message_function) (tree->connection, message, user_data); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif _dbus_connection_lock (tree->connection); if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) goto free_and_return; } link = next; } free_and_return: if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) { /* This hardcoded default handler does a minimal Introspect() */ result = handle_default_introspect_and_unlock (tree, message, (const char**) path); } else { #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } } while (list != NULL) { link = _dbus_list_get_first_link (&list); _dbus_object_subtree_unref (link->data); _dbus_list_remove_link (&list, link); } dbus_free_string_array (path); return result; } /** * Looks up the data passed to _dbus_object_tree_register() for a * handler at the given path. * * @param tree the global object tree * @param path NULL-terminated array of path elements giving path to subtree * @returns the object's user_data or #NULL if none found */ void* _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, const char **path) { dbus_bool_t exact_match; DBusObjectSubtree *subtree; _dbus_assert (tree != NULL); _dbus_assert (path != NULL); /* Find the deepest path that covers the path in the message */ subtree = find_handler (tree, (const char**) path, &exact_match); if ((subtree == NULL) || !exact_match) { _dbus_verbose ("No object at specified path found\n"); return NULL; } return subtree->user_data; } /** * Allocates a subtree object. * * @param name name to duplicate. * @returns newly-allocated subtree */ static DBusObjectSubtree* allocate_subtree_object (const char *name) { int len; DBusObjectSubtree *subtree; const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); _dbus_assert (name != NULL); len = strlen (name); subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); if (subtree == NULL) return NULL; memcpy (subtree->name, name, len + 1); return subtree; } static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, const DBusObjectPathVTable *vtable, void *user_data) { DBusObjectSubtree *subtree; subtree = allocate_subtree_object (name); if (subtree == NULL) goto oom; _dbus_assert (name != NULL); subtree->parent = NULL; if (vtable) { subtree->message_function = vtable->message_function; subtree->unregister_function = vtable->unregister_function; } else { subtree->message_function = NULL; subtree->unregister_function = NULL; } subtree->user_data = user_data; _dbus_atomic_inc (&subtree->refcount); subtree->subtrees = NULL; subtree->n_subtrees = 0; subtree->max_subtrees = 0; subtree->invoke_as_fallback = FALSE; return subtree; oom: return NULL; } static DBusObjectSubtree * _dbus_object_subtree_ref (DBusObjectSubtree *subtree) { #ifdef DBUS_DISABLE_ASSERT _dbus_atomic_inc (&subtree->refcount); #else dbus_int32_t old_value; old_value = _dbus_atomic_inc (&subtree->refcount); _dbus_assert (old_value > 0); #endif return subtree; } static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree) { dbus_int32_t old_value; old_value = _dbus_atomic_dec (&subtree->refcount); _dbus_assert (old_value > 0); if (old_value == 1) { _dbus_assert (subtree->unregister_function == NULL); _dbus_assert (subtree->message_function == NULL); dbus_free (subtree->subtrees); dbus_free (subtree); } } /** * Lists the registered fallback handlers and object path handlers at * the given parent_path. The returned array should be freed with * dbus_free_string_array(). * * @param tree the object tree * @param parent_path the path to list the child handlers of * @param child_entries returns #NULL-terminated array of children * @returns #FALSE if no memory to allocate the child entries */ dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, const char **parent_path, char ***child_entries) { dbus_bool_t result; result = _dbus_object_tree_list_registered_unlocked (tree, parent_path, child_entries); #ifdef DBUS_ENABLE_EMBEDDED_TESTS if (tree->connection) #endif { _dbus_verbose ("unlock\n"); _dbus_connection_unlock (tree->connection); } return result; } /** Set to 1 to get a bunch of spew about disassembling the path string */ #define VERBOSE_DECOMPOSE 0 /** * Decompose an object path. A path of just "/" is * represented as an empty vector of strings. * The path need not be nul terminated. * * @param data the path data * @param len the length of the path string * @param path address to store new object path * @param path_len length of stored path */ dbus_bool_t _dbus_decompose_path (const char* data, int len, char ***path, int *path_len) { char **retval; int n_components; int i, j, comp; _dbus_assert (data != NULL); _dbus_assert (path != NULL); #if VERBOSE_DECOMPOSE _dbus_verbose ("Decomposing path \"%s\"\n", data); #endif n_components = 0; if (len > 1) /* if path is not just "/" */ { i = 0; while (i < len) { _dbus_assert (data[i] != '\0'); if (data[i] == '/') n_components += 1; ++i; } } retval = dbus_new0 (char*, n_components + 1); if (retval == NULL) return FALSE; comp = 0; if (n_components == 0) i = 1; else i = 0; while (comp < n_components) { _dbus_assert (i < len); if (data[i] == '/') ++i; j = i; while (j < len && data[j] != '/') ++j; /* Now [i, j) is the path component */ _dbus_assert (i < j); _dbus_assert (data[i] != '/'); _dbus_assert (j == len || data[j] == '/'); #if VERBOSE_DECOMPOSE _dbus_verbose (" (component in [%d,%d))\n", i, j); #endif retval[comp] = _dbus_memdup (&data[i], j - i + 1); if (retval[comp] == NULL) { dbus_free_string_array (retval); return FALSE; } retval[comp][j-i] = '\0'; #if VERBOSE_DECOMPOSE _dbus_verbose (" (component %d = \"%s\")\n", comp, retval[comp]); #endif ++comp; i = j; } _dbus_assert (i == len); *path = retval; if (path_len) *path_len = n_components; return TRUE; } /** @} */ static char* flatten_path (const char **path) { DBusString str; char *s; if (!_dbus_string_init (&str)) return NULL; if (path[0] == NULL) { if (!_dbus_string_append_byte (&str, '/')) goto nomem; } else { int i; i = 0; while (path[i]) { if (!_dbus_string_append_byte (&str, '/')) goto nomem; if (!_dbus_string_append (&str, path[i])) goto nomem; ++i; } } if (!_dbus_string_steal_data (&str, &s)) goto nomem; _dbus_string_free (&str); return s; nomem: _dbus_string_free (&str); return NULL; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "dbus-test.h" #include typedef enum { STR_EQUAL, STR_PREFIX, STR_DIFFERENT } StrComparison; /* Returns TRUE if container is a parent of child */ static StrComparison path_contains (const char **container, const char **child) { int i; i = 0; while (child[i] != NULL) { int v; if (container[i] == NULL) return STR_PREFIX; /* container ran out, child continues; * thus the container is a parent of the * child. */ _dbus_assert (container[i] != NULL); _dbus_assert (child[i] != NULL); v = strcmp (container[i], child[i]); if (v != 0) return STR_DIFFERENT; /* they overlap until here and then are different, * not overlapping */ ++i; } /* Child ran out; if container also did, they are equal; * otherwise, the child is a parent of the container. */ if (container[i] == NULL) return STR_EQUAL; else return STR_DIFFERENT; } #if 0 static void spew_subtree_recurse (DBusObjectSubtree *subtree, int indent) { int i; i = 0; while (i < indent) { _dbus_verbose (" "); ++i; } _dbus_verbose ("%s (%d children)\n", subtree->name, subtree->n_subtrees); i = 0; while (i < subtree->n_subtrees) { spew_subtree_recurse (subtree->subtrees[i], indent + 2); ++i; } } static void spew_tree (DBusObjectTree *tree) { spew_subtree_recurse (tree->root, 0); } #endif /** * Callback data used in tests */ typedef struct { const char **path; /**< Path */ dbus_bool_t handler_fallback; /**< true if the handler may be called as fallback */ dbus_bool_t message_handled; /**< Gets set to true if message handler called */ dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */ } TreeTestData; static void test_unregister_function (DBusConnection *connection, void *user_data) { TreeTestData *ttd = user_data; ttd->handler_unregistered = TRUE; } static DBusHandlerResult test_message_function (DBusConnection *connection, DBusMessage *message, void *user_data) { TreeTestData *ttd = user_data; ttd->message_handled = TRUE; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static dbus_bool_t do_register (DBusObjectTree *tree, const char **path, dbus_bool_t fallback, int i, TreeTestData *tree_test_data) { DBusObjectPathVTable vtable = { test_unregister_function, test_message_function, NULL }; tree_test_data[i].message_handled = FALSE; tree_test_data[i].handler_unregistered = FALSE; tree_test_data[i].handler_fallback = fallback; tree_test_data[i].path = path; if (!_dbus_object_tree_register (tree, fallback, path, &vtable, &tree_test_data[i], NULL)) return FALSE; _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == &tree_test_data[i]); return TRUE; } static dbus_bool_t do_test_dispatch (DBusObjectTree *tree, const char **path, int i, TreeTestData *tree_test_data, int n_test_data) { DBusMessage *message; int j; DBusHandlerResult result; char *flat; message = NULL; flat = flatten_path (path); if (flat == NULL) goto oom; message = dbus_message_new_method_call (NULL, flat, "org.freedesktop.TestInterface", "Foo"); dbus_free (flat); if (message == NULL) goto oom; j = 0; while (j < n_test_data) { tree_test_data[j].message_handled = FALSE; ++j; } result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL); if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) goto oom; _dbus_assert (tree_test_data[i].message_handled); j = 0; while (j < n_test_data) { if (tree_test_data[j].message_handled) { if (tree_test_data[j].handler_fallback) _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_DIFFERENT); else _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); } else { if (tree_test_data[j].handler_fallback) _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_DIFFERENT); else _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); } ++j; } dbus_message_unref (message); return TRUE; oom: if (message) dbus_message_unref (message); return FALSE; } static size_t string_array_length (const char **array) { size_t i; for (i = 0; array[i]; i++) ; return i; } typedef struct { const char *path; const char *result[20]; } DecomposePathTest; static DecomposePathTest decompose_tests[] = { { "/foo", { "foo", NULL } }, { "/foo/bar", { "foo", "bar", NULL } }, { "/", { NULL } }, { "/a/b", { "a", "b", NULL } }, { "/a/b/c", { "a", "b", "c", NULL } }, { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, { "/foo/bar/q", { "foo", "bar", "q", NULL } }, { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } }; static dbus_bool_t run_decompose_tests (void) { int i; i = 0; while (i < _DBUS_N_ELEMENTS (decompose_tests)) { char **result; int result_len; int expected_len; if (!_dbus_decompose_path (decompose_tests[i].path, strlen (decompose_tests[i].path), &result, &result_len)) return FALSE; expected_len = string_array_length (decompose_tests[i].result); if (result_len != (int) string_array_length ((const char**)result) || expected_len != result_len || path_contains (decompose_tests[i].result, (const char**) result) != STR_EQUAL) { int real_len = string_array_length ((const char**)result); _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", decompose_tests[i].path, expected_len, result_len, real_len); _dbus_warn ("Decompose resulted in elements: { "); i = 0; while (i < real_len) { _dbus_warn ("\"%s\"%s", result[i], (i + 1) == real_len ? "" : ", "); ++i; } _dbus_warn ("}\n"); _dbus_assert_not_reached ("path decompose failed\n"); } dbus_free_string_array (result); ++i; } return TRUE; } static DBusObjectSubtree* find_subtree_registered_or_unregistered (DBusObjectTree *tree, const char **path) { #if VERBOSE_FIND _dbus_verbose ("Looking for exact subtree, registered or unregistered\n"); #endif return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); } static dbus_bool_t object_tree_test_iteration (void *data) { const char *path0[] = { NULL }; const char *path1[] = { "foo", NULL }; const char *path2[] = { "foo", "bar", NULL }; const char *path3[] = { "foo", "bar", "baz", NULL }; const char *path4[] = { "foo", "bar", "boo", NULL }; const char *path5[] = { "blah", NULL }; const char *path6[] = { "blah", "boof", NULL }; const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; const char *path8[] = { "childless", NULL }; const char *path9[] = { "blah", "a", NULL }; const char *path10[] = { "blah", "b", NULL }; const char *path11[] = { "blah", "c", NULL }; const char *path12[] = { "blah", "a", "d", NULL }; const char *path13[] = { "blah", "b", "d", NULL }; const char *path14[] = { "blah", "c", "d", NULL }; DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL }; DBusObjectTree *tree; TreeTestData tree_test_data[9]; int i; dbus_bool_t exact_match; if (!run_decompose_tests ()) return FALSE; tree = NULL; tree = _dbus_object_tree_new (NULL); if (tree == NULL) goto out; if (!do_register (tree, path0, TRUE, 0, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); if (!do_register (tree, path1, TRUE, 1, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); if (!do_register (tree, path3, TRUE, 3, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); if (!do_register (tree, path4, TRUE, 4, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); if (!do_register (tree, path5, TRUE, 5, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); if (!do_register (tree, path6, TRUE, 6, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); if (!do_register (tree, path7, TRUE, 7, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); if (!do_register (tree, path8, TRUE, 8, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); /* test the list_registered function */ { const char *root[] = { NULL }; char **child_entries; int nb; _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); if (child_entries != NULL) { nb = string_array_length ((const char**)child_entries); _dbus_assert (nb == 1); dbus_free_string_array (child_entries); } _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); if (child_entries != NULL) { nb = string_array_length ((const char**)child_entries); _dbus_assert (nb == 2); dbus_free_string_array (child_entries); } _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); if (child_entries != NULL) { nb = string_array_length ((const char**)child_entries); _dbus_assert (nb == 0); dbus_free_string_array (child_entries); } _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); if (child_entries != NULL) { nb = string_array_length ((const char**)child_entries); _dbus_assert (nb == 3); dbus_free_string_array (child_entries); } } /* Check that destroying tree calls unregister funcs */ _dbus_object_tree_unref (tree); i = 0; while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) { _dbus_assert (tree_test_data[i].handler_unregistered); _dbus_assert (!tree_test_data[i].message_handled); ++i; } /* Now start again and try the individual unregister function */ tree = _dbus_object_tree_new (NULL); if (tree == NULL) goto out; if (!do_register (tree, path0, TRUE, 0, tree_test_data)) goto out; if (!do_register (tree, path1, TRUE, 1, tree_test_data)) goto out; if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; if (!do_register (tree, path3, TRUE, 3, tree_test_data)) goto out; if (!do_register (tree, path4, TRUE, 4, tree_test_data)) goto out; if (!do_register (tree, path5, TRUE, 5, tree_test_data)) goto out; if (!do_register (tree, path6, TRUE, 6, tree_test_data)) goto out; if (!do_register (tree, path7, TRUE, 7, tree_test_data)) goto out; if (!do_register (tree, path8, TRUE, 8, tree_test_data)) goto out; _dbus_object_tree_unregister_and_unlock (tree, path0); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path1); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path3); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path4); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path5); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path6); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path7); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path8); _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree (tree, path5, NULL)); _dbus_assert (!find_subtree (tree, path6, NULL)); _dbus_assert (!find_subtree (tree, path7, NULL)); _dbus_assert (!find_subtree (tree, path8, NULL)); i = 0; while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) { _dbus_assert (tree_test_data[i].handler_unregistered); _dbus_assert (!tree_test_data[i].message_handled); ++i; } /* Test removal of newly-childless unregistered nodes */ if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); /* Test that unregistered parents cannot be freed out from under their children */ if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); #if 0 /* This triggers the "Attempted to unregister path ..." warning message */ _dbus_object_tree_unregister_and_unlock (tree, path1); #endif _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); /* Test that registered parents cannot be freed out from under their children, and that if they are unregistered before their children, they are still freed when their children are unregistered */ if (!do_register (tree, path1, TRUE, 1, tree_test_data)) goto out; if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path1); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (find_subtree (tree, path2, NULL)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_assert (!find_subtree (tree, path1, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); /* Test with NULL unregister_function and user_data */ if (!_dbus_object_tree_register (tree, TRUE, path2, &test_vtable, NULL, NULL)) goto out; _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_assert (!find_subtree (tree, path2, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); /* Test freeing a long path */ if (!do_register (tree, path3, TRUE, 3, tree_test_data)) goto out; _dbus_object_tree_unregister_and_unlock (tree, path3); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); /* Test freeing multiple children from the same path */ if (!do_register (tree, path3, TRUE, 3, tree_test_data)) goto out; if (!do_register (tree, path4, TRUE, 4, tree_test_data)) goto out; _dbus_assert (find_subtree (tree, path3, NULL)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path3); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); _dbus_assert (find_subtree (tree, path4, NULL)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path4)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); _dbus_object_tree_unregister_and_unlock (tree, path4); _dbus_assert (!find_subtree (tree, path4, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path4)); _dbus_assert (!find_subtree (tree, path3, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); /* Test subtree removal */ if (!_dbus_object_tree_register (tree, TRUE, path12, &test_vtable, NULL, NULL)) goto out; _dbus_assert (find_subtree (tree, path12, NULL)); if (!_dbus_object_tree_register (tree, TRUE, path13, &test_vtable, NULL, NULL)) goto out; _dbus_assert (find_subtree (tree, path13, NULL)); if (!_dbus_object_tree_register (tree, TRUE, path14, &test_vtable, NULL, NULL)) goto out; _dbus_assert (find_subtree (tree, path14, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path12); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12)); _dbus_assert (find_subtree (tree, path13, NULL)); _dbus_assert (find_subtree (tree, path14, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); if (!_dbus_object_tree_register (tree, TRUE, path12, &test_vtable, NULL, NULL)) goto out; _dbus_assert (find_subtree (tree, path12, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path13); _dbus_assert (find_subtree (tree, path12, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13)); _dbus_assert (find_subtree (tree, path14, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); if (!_dbus_object_tree_register (tree, TRUE, path13, &test_vtable, NULL, NULL)) goto out; _dbus_assert (find_subtree (tree, path13, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path14); _dbus_assert (find_subtree (tree, path12, NULL)); _dbus_assert (find_subtree (tree, path13, NULL)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path14)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path11)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); _dbus_object_tree_unregister_and_unlock (tree, path12); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9)); _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); _dbus_object_tree_unregister_and_unlock (tree, path13); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10)); _dbus_assert (!find_subtree_registered_or_unregistered (tree, path5)); #if 0 /* Test attempting to unregister non-existent paths. These trigger "Attempted to unregister path ..." warning messages */ _dbus_object_tree_unregister_and_unlock (tree, path0); _dbus_object_tree_unregister_and_unlock (tree, path1); _dbus_object_tree_unregister_and_unlock (tree, path2); _dbus_object_tree_unregister_and_unlock (tree, path3); _dbus_object_tree_unregister_and_unlock (tree, path4); #endif /* Register it all again, and test dispatch */ if (!do_register (tree, path0, TRUE, 0, tree_test_data)) goto out; if (!do_register (tree, path1, FALSE, 1, tree_test_data)) goto out; if (!do_register (tree, path2, TRUE, 2, tree_test_data)) goto out; if (!do_register (tree, path3, TRUE, 3, tree_test_data)) goto out; if (!do_register (tree, path4, TRUE, 4, tree_test_data)) goto out; if (!do_register (tree, path5, TRUE, 5, tree_test_data)) goto out; if (!do_register (tree, path6, FALSE, 6, tree_test_data)) goto out; if (!do_register (tree, path7, TRUE, 7, tree_test_data)) goto out; if (!do_register (tree, path8, TRUE, 8, tree_test_data)) goto out; #if 0 spew_tree (tree); #endif if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) goto out; out: if (tree) { /* test ref */ _dbus_object_tree_ref (tree); _dbus_object_tree_unref (tree); _dbus_object_tree_unref (tree); } return TRUE; } /** * @ingroup DBusObjectTree * Unit test for DBusObjectTree * @returns #TRUE on success. */ dbus_bool_t _dbus_object_tree_test (void) { _dbus_test_oom_handling ("object tree", object_tree_test_iteration, NULL); return TRUE; } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-nonce.c0000644000175000017500000003115612602773110015701 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-nonce.c Nonce handling functions used by nonce-tcp (internal to D-Bus implementation) * * Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include // major sections of this file are modified code from libassuan, (C) FSF #include "dbus-nonce.h" #include "dbus-internals.h" #include "dbus-protocol.h" #include "dbus-sysdeps.h" #include static dbus_bool_t do_check_nonce (DBusSocket fd, const DBusString *nonce, DBusError *error) { DBusString buffer; DBusString p; size_t nleft; dbus_bool_t result; int n; _DBUS_ASSERT_ERROR_IS_CLEAR (error); nleft = 16; if ( !_dbus_string_init (&buffer) || !_dbus_string_init (&p) ) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } while (nleft) { int saved_errno; n = _dbus_read_socket (fd, &p, nleft); saved_errno = _dbus_save_socket_errno (); if (n == -1 && _dbus_get_is_errno_eintr (saved_errno)) ; else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) _dbus_sleep_milliseconds (100); else if (n==-1) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd ); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } else if (!n) { _dbus_string_free (&p); _dbus_string_free (&buffer); dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd ); return FALSE; } else { if (!_dbus_string_append_len (&buffer, _dbus_string_get_const_data (&p), n)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } nleft -= n; } } result = _dbus_string_equal_len (&buffer, nonce, 16); if (!result) dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd ); _dbus_string_free (&p); _dbus_string_free (&buffer); return result; } /** * reads the nonce from the nonce file and stores it in a string * * @param fname the file to read the nonce from * @param nonce returns the nonce. Must be an initialized string, the nonce will be appended. * @param error error object to report possible errors * @return FALSE iff reading the nonce fails (error is set then) */ dbus_bool_t _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error) { FILE *fp; char buffer[17]; size_t nread; buffer[sizeof buffer - 1] = '\0'; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname)); fp = fopen (_dbus_string_get_const_data (fname), "rb"); if (!fp) { dbus_set_error (error, _dbus_error_from_system_errno (), "Failed to open %s for read: %s", _dbus_string_get_const_data (fname), _dbus_strerror_from_errno ()); return FALSE; } nread = fread (buffer, 1, sizeof buffer - 1, fp); fclose (fp); if (!nread) { dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname)); return FALSE; } if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 )) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } return TRUE; } DBusSocket _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefile) { DBusSocket fd; DBusString nonce; _dbus_assert (noncefile != NULL); if (!_dbus_string_init (&nonce)) return _dbus_socket_get_invalid (); //PENDING(kdab): set better errors if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE) return _dbus_socket_get_invalid (); fd = _dbus_accept (listen_fd); if (!_dbus_socket_is_valid (fd)) return fd; if (do_check_nonce(fd, &nonce, NULL) != TRUE) { _dbus_verbose ("nonce check failed. Closing socket.\n"); _dbus_close_socket(fd, NULL); return _dbus_socket_get_invalid (); } return fd; } static dbus_bool_t generate_and_write_nonce (const DBusString *filename, DBusError *error) { DBusString nonce; dbus_bool_t ret; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&nonce)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } if (!_dbus_generate_random_bytes (&nonce, 16, error)) { _dbus_string_free (&nonce); return FALSE; } ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error); _dbus_string_free (&nonce); return ret; } /** * sends the nonce over a given socket. Blocks while doing so. * * @param fd the file descriptor to write the nonce data to (usually a socket) * @param noncefile the noncefile location to read the nonce from * @param error contains error details if FALSE is returned * @return TRUE iff the nonce was successfully sent. Note that this does not * indicate whether the server accepted the nonce. */ dbus_bool_t _dbus_send_nonce (DBusSocket fd, const DBusString *noncefile, DBusError *error) { dbus_bool_t read_result; int send_result; DBusString nonce; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_dbus_string_get_length (noncefile) == 0) return FALSE; if (!_dbus_string_init (&nonce)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } read_result = _dbus_read_nonce (noncefile, &nonce, error); if (!read_result) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&nonce); return FALSE; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce)); _dbus_string_free (&nonce); if (send_result == -1) { dbus_set_error (error, _dbus_error_from_system_errno (), "Failed to send nonce (fd=%d): %s", fd, _dbus_strerror_from_errno ()); return FALSE; } return TRUE; } static dbus_bool_t do_noncefile_create (DBusNonceFile *noncefile, DBusError *error, dbus_bool_t use_subdir) { DBusString randomStr; const char *tmp; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (noncefile); if (!_dbus_string_init (&randomStr)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_generate_random_ascii (&randomStr, 8, error)) { goto on_error; } tmp = _dbus_get_tmpdir (); if (!_dbus_string_init (&noncefile->dir) || tmp == NULL || !_dbus_string_append (&noncefile->dir, tmp)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (use_subdir) { if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-") || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) ) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_string_init (&noncefile->path) || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0) || !_dbus_string_append (&noncefile->path, "/nonce")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_create_directory (&noncefile->dir, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto on_error; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); } else { if (!_dbus_string_init (&noncefile->path) || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0) || !_dbus_string_append (&noncefile->path, "/dbus_nonce-") || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } } if (!generate_and_write_nonce (&noncefile->path, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); if (use_subdir) _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead goto on_error; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_string_free (&randomStr); return TRUE; on_error: if (use_subdir) _dbus_delete_directory (&noncefile->dir, NULL); _dbus_string_free (&noncefile->dir); _dbus_string_free (&noncefile->path); _dbus_string_free (&randomStr); return FALSE; } #ifdef DBUS_WIN /** * creates a nonce file in a user-readable location and writes a generated nonce to it * * @param noncefile returns the nonce file location * @param error error details if creating the nonce file fails * @return TRUE iff the nonce file was successfully created */ dbus_bool_t _dbus_noncefile_create (DBusNonceFile *noncefile, DBusError *error) { return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE); } /** * deletes the noncefile and frees the DBusNonceFile object. * * @param noncefile the nonce file to delete. Contents will be freed. * @param error error details if the nonce file could not be deleted * @return TRUE */ dbus_bool_t _dbus_noncefile_delete (DBusNonceFile *noncefile, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_delete_file (&noncefile->path, error); _dbus_string_free (&noncefile->dir); _dbus_string_free (&noncefile->path); return TRUE; } #else /** * creates a nonce file in a user-readable location and writes a generated nonce to it. * Initializes the noncefile object. * * @param noncefile returns the nonce file location * @param error error details if creating the nonce file fails * @return TRUE iff the nonce file was successfully created */ dbus_bool_t _dbus_noncefile_create (DBusNonceFile *noncefile, DBusError *error) { return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE); } /** * deletes the noncefile and frees the DBusNonceFile object. * * @param noncefile the nonce file to delete. Contents will be freed. * @param error error details if the nonce file could not be deleted * @return TRUE */ dbus_bool_t _dbus_noncefile_delete (DBusNonceFile *noncefile, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_delete_directory (&noncefile->dir, error); _dbus_string_free (&noncefile->dir); _dbus_string_free (&noncefile->path); return TRUE; } #endif /** * returns the absolute file path of the nonce file * * @param noncefile an initialized noncefile object * @return the absolute path of the nonce file */ const DBusString* _dbus_noncefile_get_path (const DBusNonceFile *noncefile) { _dbus_assert (noncefile); return &noncefile->path; } /** * reads data from a file descriptor and checks if the received data matches * the data in the given noncefile. * * @param fd the file descriptor to read the nonce from * @param noncefile the nonce file to check the received data against * @param error error details on fail * @return TRUE iff a nonce could be successfully read from the file descriptor * and matches the nonce from the given nonce file */ dbus_bool_t _dbus_noncefile_check_nonce (DBusSocket fd, const DBusNonceFile *noncefile, DBusError* error) { return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error); } /** @} end of nonce */ dbus-1.10.6/dbus/dbus-nonce.h0000644000175000017500000000450312602773110015702 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-nonce.h Nonce handling functions used by nonce-tcp (internal to D-Bus implementation) * * Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DBUS_NONCE_H #define DBUS_NONCE_H #include #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusNonceFile DBusNonceFile; struct DBusNonceFile { DBusString path; DBusString dir; }; // server dbus_bool_t _dbus_noncefile_create (DBusNonceFile *noncefile, DBusError *error); dbus_bool_t _dbus_noncefile_delete (DBusNonceFile *noncefile, DBusError *error); dbus_bool_t _dbus_noncefile_check_nonce (DBusSocket fd, const DBusNonceFile *noncefile, DBusError *error); const DBusString* _dbus_noncefile_get_path (const DBusNonceFile *noncefile); DBusSocket _dbus_accept_with_noncefile(DBusSocket listen_fd, const DBusNonceFile *noncefile); // shared dbus_bool_t _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError *error); // client dbus_bool_t _dbus_send_nonce (DBusSocket fd, const DBusString *noncefile, DBusError *error); DBUS_END_DECLS #endif /* DBUS_NONCE_H */ dbus-1.10.6/dbus/dbus-misc.c0000644000175000017500000002012412602773110015523 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-misc.c A few assorted public functions that don't fit elsewhere * * Copyright (C) 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-misc.h" #include "dbus-internals.h" #include "dbus-string.h" /** * @defgroup DBusMisc Miscellaneous * @ingroup DBus * @brief Miscellaneous API that doesn't cleanly fit anywhere else * * @{ */ /** * Obtains the machine UUID of the machine this process is running on. * * The returned string must be freed with dbus_free(). * * This UUID is guaranteed to remain the same until the next reboot * (unless the sysadmin foolishly changes it and screws themselves). * It will usually remain the same across reboots also, but hardware * configuration changes or rebuilding the machine could break that. * * The idea is that two processes with the same machine ID should be * able to use shared memory, UNIX domain sockets, process IDs, and other * features of the OS that require both processes to be running * on the same OS kernel instance. * * The machine ID can also be used to create unique per-machine * instances. For example, you could use it in bus names or * X selection names. * * The machine ID is preferred over the machine hostname, because * the hostname is frequently set to "localhost.localdomain" and * may also change at runtime. * * You can get the machine ID of a remote application by invoking the * method GetMachineId from interface org.freedesktop.DBus.Peer. * * If the remote application has the same machine ID as the one * returned by this function, then the remote application is on the * same machine as your application. * * The UUID is not a UUID in the sense of RFC4122; the details * are explained in the D-Bus specification. * * @returns a 32-byte-long hex-encoded UUID string, or #NULL if insufficient memory */ char* dbus_get_local_machine_id (void) { DBusString uuid; char *s; s = NULL; if (!_dbus_string_init (&uuid)) return NULL; /* The documentation says dbus_get_local_machine_id() only fails on OOM; * this can actually also fail if the D-Bus installation is faulty * (no UUID) *and* reading a new random UUID fails, but we have no way * to report that */ if (!_dbus_get_local_machine_uuid_encoded (&uuid, NULL) || !_dbus_string_steal_data (&uuid, &s)) { _dbus_string_free (&uuid); return NULL; } else { _dbus_string_free (&uuid); return s; } } /** * @def DBUS_MAJOR_VERSION * * The COMPILE TIME major version of libdbus, that is, the "X" in "X.Y.Z", * as an integer literal. Consider carefully whether to use this or the * runtime version from dbus_get_version(). */ /** * @def DBUS_MINOR_VERSION * * The COMPILE TIME minor version of libdbus, that is, the "Y" in "X.Y.Z", * as an integer literal. Consider carefully whether to use this or the * runtime version from dbus_get_version(). */ /** * @def DBUS_MICRO_VERSION * * The COMPILE TIME micro version of libdbus, that is, the "Z" in "X.Y.Z", * as an integer literal. Consider carefully whether to use this or the * runtime version from dbus_get_version(). */ /** * @def DBUS_VERSION * * The COMPILE TIME version of libdbus, as a single integer that has 0 in the most * significant byte, the major version in the next most significant byte, * the minor version in the third most significant, and the micro version in the * least significant byte. This means two DBUS_VERSION can be compared to see * which is higher. * * Consider carefully whether to use this or the runtime version from * dbus_get_version(). */ /** * @def DBUS_VERSION_STRING * * The COMPILE TIME version of libdbus, as a string "X.Y.Z". * * Consider carefully whether to use this or the runtime version from * dbus_get_version(). */ /** * Gets the DYNAMICALLY LINKED version of libdbus. Alternatively, there * are macros #DBUS_MAJOR_VERSION, #DBUS_MINOR_VERSION, #DBUS_MICRO_VERSION, * and #DBUS_VERSION which allow you to test the VERSION YOU ARE COMPILED AGAINST. * In other words, you can get either the runtime or the compile-time version. * Think carefully about which of these you want in a given case. * * The libdbus full version number is "MAJOR.MINOR.MICRO" where the * MINOR changes if API is added, and the MICRO changes with each * release of a MAJOR.MINOR series. The MINOR is an odd number for * development releases and an even number for stable releases. * * @param major_version_p pointer to return the major version, or #NULL * @param minor_version_p pointer to return the minor version, or #NULL * @param micro_version_p pointer to return the micro version, or #NULL * */ void dbus_get_version (int *major_version_p, int *minor_version_p, int *micro_version_p) { if (major_version_p) *major_version_p = DBUS_MAJOR_VERSION; if (minor_version_p) *minor_version_p = DBUS_MINOR_VERSION; if (micro_version_p) *micro_version_p = DBUS_MICRO_VERSION; } /** @} */ /* End of public API */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "dbus-test.h" #include dbus_bool_t _dbus_misc_test (void) { int major, minor, micro; DBusString str; /* make sure we don't crash on NULL */ dbus_get_version (NULL, NULL, NULL); /* Now verify that all the compile-time version stuff * is right and matches the runtime. These tests * are mostly intended to catch various kinds of * typo (mixing up major and minor, that sort of thing). */ dbus_get_version (&major, &minor, µ); _dbus_assert (major == DBUS_MAJOR_VERSION); _dbus_assert (minor == DBUS_MINOR_VERSION); _dbus_assert (micro == DBUS_MICRO_VERSION); #define MAKE_VERSION(x, y, z) (((x) << 16) | ((y) << 8) | (z)) /* check that MAKE_VERSION works and produces the intended ordering */ _dbus_assert (MAKE_VERSION (1, 0, 0) > MAKE_VERSION (0, 0, 0)); _dbus_assert (MAKE_VERSION (1, 1, 0) > MAKE_VERSION (1, 0, 0)); _dbus_assert (MAKE_VERSION (1, 1, 1) > MAKE_VERSION (1, 1, 0)); _dbus_assert (MAKE_VERSION (2, 0, 0) > MAKE_VERSION (1, 1, 1)); _dbus_assert (MAKE_VERSION (2, 1, 0) > MAKE_VERSION (1, 1, 1)); _dbus_assert (MAKE_VERSION (2, 1, 1) > MAKE_VERSION (1, 1, 1)); /* check DBUS_VERSION */ _dbus_assert (MAKE_VERSION (major, minor, micro) == DBUS_VERSION); /* check that ordering works with DBUS_VERSION */ _dbus_assert (MAKE_VERSION (major - 1, minor, micro) < DBUS_VERSION); _dbus_assert (MAKE_VERSION (major, minor - 1, micro) < DBUS_VERSION); _dbus_assert (MAKE_VERSION (major, minor, micro - 1) < DBUS_VERSION); _dbus_assert (MAKE_VERSION (major + 1, minor, micro) > DBUS_VERSION); _dbus_assert (MAKE_VERSION (major, minor + 1, micro) > DBUS_VERSION); _dbus_assert (MAKE_VERSION (major, minor, micro + 1) > DBUS_VERSION); /* Check DBUS_VERSION_STRING */ if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("no memory"); if (!(_dbus_string_append_int (&str, major) && _dbus_string_append_byte (&str, '.') && _dbus_string_append_int (&str, minor) && _dbus_string_append_byte (&str, '.') && _dbus_string_append_int (&str, micro))) _dbus_assert_not_reached ("no memory"); _dbus_assert (_dbus_string_equal_c_str (&str, DBUS_VERSION_STRING)); _dbus_string_free (&str); return TRUE; } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif dbus-1.10.6/dbus/dbus-message-private.h0000644000175000017500000001174112602773110017676 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-private.h header shared between dbus-message.c and dbus-message-util.c * * Copyright (C) 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MESSAGE_PRIVATE_H #define DBUS_MESSAGE_PRIVATE_H #include #include #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusMessageInternals * @{ */ /** * @typedef DBusMessageLoader * * The DBusMessageLoader object encapsulates the process of converting * a byte stream into a series of DBusMessage. It buffers the incoming * bytes as efficiently as possible, and generates a queue of * messages. DBusMessageLoader is typically used as part of a * DBusTransport implementation. The DBusTransport then hands off * the loaded messages to a DBusConnection, making the messages * visible to the application. * * @todo write tests for break-loader that a) randomly delete header * fields and b) set string fields to zero-length and other funky * values. * */ /** * Implementation details of DBusMessageLoader. * All members are private. */ struct DBusMessageLoader { int refcount; /**< Reference count. */ DBusString data; /**< Buffered data */ DBusList *messages; /**< Complete messages. */ long max_message_size; /**< Maximum size of a message */ long max_message_unix_fds; /**< Maximum unix fds in a message */ DBusValidity corruption_reason; /**< why we were corrupted */ unsigned int corrupted : 1; /**< We got broken data, and are no longer working */ unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */ #ifdef HAVE_UNIX_FD_PASSING unsigned int unix_fds_outstanding : 1; /**< Someone is using the unix fd array to read */ int *unix_fds; /**< File descriptors that have been read from the transport but not yet been handed to any message. Array will be allocated at first use. */ unsigned n_unix_fds_allocated; /**< Number of file descriptors this array has space for */ unsigned n_unix_fds; /**< Number of valid file descriptors in array */ void (* unix_fds_change) (void *); /**< Notify when the pending fds change */ void *unix_fds_change_data; #endif }; /** How many bits are in the changed_stamp used to validate iterators */ #define CHANGED_STAMP_BITS 21 /** * @brief Internals of DBusMessage * * Object representing a message received from or to be sent to * another application. This is an opaque object, all members * are private. */ struct DBusMessage { DBusAtomic refcount; /**< Reference count */ DBusHeader header; /**< Header network data and associated cache */ DBusString body; /**< Body network data. */ unsigned int locked : 1; /**< Message being sent, no modifications allowed. */ #ifndef DBUS_DISABLE_CHECKS unsigned int in_cache : 1; /**< Has been "freed" since it's in the cache (this is a debug feature) */ #endif DBusList *counters; /**< 0-N DBusCounter used to track message size/unix fds. */ long size_counter_delta; /**< Size we incremented the size counters by. */ dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ #ifndef DBUS_DISABLE_CHECKS int generation; /**< _dbus_current_generation when message was created */ #endif #ifdef HAVE_UNIX_FD_PASSING int *unix_fds; /**< Unix file descriptors associated with this message. These are closed when the message is destroyed, hence make sure to dup() them when adding or removing them here. */ unsigned n_unix_fds; /**< Number of valid fds in the array */ unsigned n_unix_fds_allocated; /**< Allocated size of the array */ long unix_fd_counter_delta; /**< Size we incremented the unix fd counter by */ #endif }; DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter, DBusError *error, int first_arg_type, va_list var_args); /** @} */ DBUS_END_DECLS #endif /* DBUS_MESSAGE_H */ dbus-1.10.6/dbus/dbus-message-internal.h0000644000175000017500000001330212602773110020033 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-internal.h DBusMessage object internal interfaces * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MESSAGE_INTERNAL_H #define DBUS_MESSAGE_INTERNAL_H #include #include #include #include DBUS_BEGIN_DECLS #ifdef DBUS_ENABLE_VERBOSE_MODE void _dbus_message_trace_ref (DBusMessage *message, int old_refcount, int new_refcount, const char *why); #else /* this bypasses any "unused" warnings for the old and new refcount */ #define _dbus_message_trace_ref(m, o, n, w) \ do \ {\ (void) (o); \ (void) (n); \ } while (0) #endif typedef struct DBusMessageLoader DBusMessageLoader; void _dbus_message_get_network_data (DBusMessage *message, const DBusString **header, const DBusString **body); DBUS_PRIVATE_EXPORT void _dbus_message_get_unix_fds (DBusMessage *message, const int **fds, unsigned *n_fds); void _dbus_message_lock (DBusMessage *message); void _dbus_message_unlock (DBusMessage *message); dbus_bool_t _dbus_message_add_counter (DBusMessage *message, DBusCounter *counter); void _dbus_message_add_counter_link (DBusMessage *message, DBusList *link); void _dbus_message_remove_counter (DBusMessage *message, DBusCounter *counter); DBUS_PRIVATE_EXPORT DBusMessageLoader* _dbus_message_loader_new (void); DBUS_PRIVATE_EXPORT DBusMessageLoader* _dbus_message_loader_ref (DBusMessageLoader *loader); DBUS_PRIVATE_EXPORT void _dbus_message_loader_unref (DBusMessageLoader *loader); DBUS_PRIVATE_EXPORT void _dbus_message_loader_get_buffer (DBusMessageLoader *loader, DBusString **buffer); DBUS_PRIVATE_EXPORT void _dbus_message_loader_return_buffer (DBusMessageLoader *loader, DBusString *buffer); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_message_loader_get_unix_fds (DBusMessageLoader *loader, int **fds, unsigned *max_n_fds); DBUS_PRIVATE_EXPORT void _dbus_message_loader_return_unix_fds (DBusMessageLoader *loader, int *fds, unsigned n_fds); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_message_loader_queue_messages (DBusMessageLoader *loader); DBusMessage* _dbus_message_loader_peek_message (DBusMessageLoader *loader); DBUS_PRIVATE_EXPORT DBusMessage* _dbus_message_loader_pop_message (DBusMessageLoader *loader); DBusList* _dbus_message_loader_pop_message_link (DBusMessageLoader *loader); void _dbus_message_loader_putback_message_link (DBusMessageLoader *loader, DBusList *link); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader); DBusValidity _dbus_message_loader_get_corruption_reason (DBusMessageLoader *loader); void _dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, long size); DBUS_PRIVATE_EXPORT long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader); void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader, long n); long _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader *loader); int _dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader); void _dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, void (* callback) (void *), void *data); typedef struct DBusInitialFDs DBusInitialFDs; DBusInitialFDs *_dbus_check_fdleaks_enter (void); void _dbus_check_fdleaks_leave (DBusInitialFDs *fds); DBUS_END_DECLS #endif /* DBUS_MESSAGE_INTERNAL_H */ dbus-1.10.6/dbus/dbus-message.c0000644000175000017500000045235212602773110016230 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message.c DBusMessage object * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. * Copyright (C) 2002, 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-marshal-recursive.h" #include "dbus-marshal-validate.h" #include "dbus-marshal-byteswap.h" #include "dbus-marshal-header.h" #include "dbus-signature.h" #include "dbus-message-private.h" #include "dbus-object-tree.h" #include "dbus-memory.h" #include "dbus-list.h" #include "dbus-threads-internal.h" #ifdef HAVE_UNIX_FD_PASSING #include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #endif #include #define _DBUS_TYPE_IS_STRINGLIKE(type) \ (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || \ type == DBUS_TYPE_OBJECT_PATH) static void dbus_message_finalize (DBusMessage *message); /** * @defgroup DBusMessageInternals DBusMessage implementation details * @ingroup DBusInternals * @brief DBusMessage private implementation details. * * The guts of DBusMessage and its methods. * * @{ */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS static dbus_bool_t _dbus_enable_message_cache (void) { static int enabled = -1; if (enabled < 0) { const char *s = _dbus_getenv ("DBUS_MESSAGE_CACHE"); enabled = TRUE; if (s && *s) { if (*s == '0') enabled = FALSE; else if (*s == '1') enabled = TRUE; else _dbus_warn ("DBUS_MESSAGE_CACHE should be 0 or 1 if set, not '%s'", s); } } return enabled; } #else /* constant expression, should be optimized away */ # define _dbus_enable_message_cache() (TRUE) #endif #ifndef _dbus_message_trace_ref void _dbus_message_trace_ref (DBusMessage *message, int old_refcount, int new_refcount, const char *why) { static int enabled = -1; _dbus_trace_ref ("DBusMessage", message, old_refcount, new_refcount, why, "DBUS_MESSAGE_TRACE", &enabled); } #endif /* Not thread locked, but strictly const/read-only so should be OK */ /** An static string representing an empty signature */ _DBUS_STRING_DEFINE_STATIC(_dbus_empty_signature_str, ""); /* these have wacky values to help trap uninitialized iterators; * but has to fit in 3 bits */ enum { DBUS_MESSAGE_ITER_TYPE_READER = 3, DBUS_MESSAGE_ITER_TYPE_WRITER = 7 }; /** typedef for internals of message iterator */ typedef struct DBusMessageRealIter DBusMessageRealIter; /** * @brief Internals of DBusMessageIter * * Object representing a position in a message. All fields are internal. */ struct DBusMessageRealIter { DBusMessage *message; /**< Message used */ dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< stamp to detect invalid iters */ dbus_uint32_t iter_type : 3; /**< whether this is a reader or writer iter */ dbus_uint32_t sig_refcount : 8; /**< depth of open_signature() */ union { DBusTypeWriter writer; /**< writer */ DBusTypeReader reader; /**< reader */ } u; /**< the type writer or reader that does all the work */ }; static void get_const_signature (DBusHeader *header, const DBusString **type_str_p, int *type_pos_p) { if (_dbus_header_get_field_raw (header, DBUS_HEADER_FIELD_SIGNATURE, type_str_p, type_pos_p)) { *type_pos_p += 1; /* skip the signature length which is 1 byte */ } else { *type_str_p = &_dbus_empty_signature_str; *type_pos_p = 0; } } /** * Swaps the message to compiler byte order if required * * @param message the message */ static void _dbus_message_byteswap (DBusMessage *message) { const DBusString *type_str; int type_pos; char byte_order; byte_order = _dbus_header_get_byte_order (&message->header); if (byte_order == DBUS_COMPILER_BYTE_ORDER) return; _dbus_verbose ("Swapping message into compiler byte order\n"); get_const_signature (&message->header, &type_str, &type_pos); _dbus_marshal_byteswap (type_str, type_pos, byte_order, DBUS_COMPILER_BYTE_ORDER, &message->body, 0); _dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER); _dbus_assert (_dbus_header_get_byte_order (&message->header) == DBUS_COMPILER_BYTE_ORDER); } /** byte-swap the message if it doesn't match our byte order. * Called only when we need the message in our own byte order, * normally when reading arrays of integers or doubles. * Otherwise should not be called since it would do needless * work. */ #define ensure_byte_order(message) _dbus_message_byteswap (message) /** * Gets the data to be sent over the network for this message. * The header and then the body should be written out. * This function is guaranteed to always return the same * data once a message is locked (with dbus_message_lock()). * * @param message the message. * @param header return location for message header data. * @param body return location for message body data. */ void _dbus_message_get_network_data (DBusMessage *message, const DBusString **header, const DBusString **body) { _dbus_assert (message->locked); *header = &message->header.data; *body = &message->body; } /** * Gets the unix fds to be sent over the network for this message. * This function is guaranteed to always return the same data once a * message is locked (with dbus_message_lock()). * * @param message the message. * @param fds return location of unix fd array * @param n_fds return number of entries in array */ void _dbus_message_get_unix_fds(DBusMessage *message, const int **fds, unsigned *n_fds) { _dbus_assert (message->locked); #ifdef HAVE_UNIX_FD_PASSING *fds = message->unix_fds; *n_fds = message->n_unix_fds; #else *fds = NULL; *n_fds = 0; #endif } /** * Sets the serial number of a message. * This can only be done once on a message. * * DBusConnection will automatically set the serial to an appropriate value * when the message is sent; this function is only needed when encapsulating * messages in another protocol, or otherwise bypassing DBusConnection. * * @param message the message * @param serial the serial */ void dbus_message_set_serial (DBusMessage *message, dbus_uint32_t serial) { _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); _dbus_header_set_serial (&message->header, serial); } /** * Adds a counter to be incremented immediately with the size/unix fds * of this message, and decremented by the size/unix fds of this * message when this message if finalized. The link contains a * counter with its refcount already incremented, but the counter * itself not incremented. Ownership of link and counter refcount is * passed to the message. * * This function may be called with locks held. As a result, the counter's * notify function is not called; the caller is expected to either call * _dbus_counter_notify() on the counter when they are no longer holding * locks, or take the same action that would be taken by the notify function. * * @param message the message * @param link link with counter as data */ void _dbus_message_add_counter_link (DBusMessage *message, DBusList *link) { /* right now we don't recompute the delta when message * size changes, and that's OK for current purposes * I think, but could be important to change later. * Do recompute it whenever there are no outstanding counters, * since it's basically free. */ if (message->counters == NULL) { message->size_counter_delta = _dbus_string_get_length (&message->header.data) + _dbus_string_get_length (&message->body); #ifdef HAVE_UNIX_FD_PASSING message->unix_fd_counter_delta = message->n_unix_fds; #endif #if 0 _dbus_verbose ("message has size %ld\n", message->size_counter_delta); #endif } _dbus_list_append_link (&message->counters, link); _dbus_counter_adjust_size (link->data, message->size_counter_delta); #ifdef HAVE_UNIX_FD_PASSING _dbus_counter_adjust_unix_fd (link->data, message->unix_fd_counter_delta); #endif } /** * Adds a counter to be incremented immediately with the size/unix fds * of this message, and decremented by the size/unix fds of this * message when this message if finalized. * * This function may be called with locks held. As a result, the counter's * notify function is not called; the caller is expected to either call * _dbus_counter_notify() on the counter when they are no longer holding * locks, or take the same action that would be taken by the notify function. * * @param message the message * @param counter the counter * @returns #FALSE if no memory */ dbus_bool_t _dbus_message_add_counter (DBusMessage *message, DBusCounter *counter) { DBusList *link; link = _dbus_list_alloc_link (counter); if (link == NULL) return FALSE; _dbus_counter_ref (counter); _dbus_message_add_counter_link (message, link); return TRUE; } /** * Removes a counter tracking the size/unix fds of this message, and * decrements the counter by the size/unix fds of this message. * * @param message the message * @param counter the counter */ void _dbus_message_remove_counter (DBusMessage *message, DBusCounter *counter) { DBusList *link; link = _dbus_list_find_last (&message->counters, counter); _dbus_assert (link != NULL); _dbus_list_remove_link (&message->counters, link); _dbus_counter_adjust_size (counter, - message->size_counter_delta); #ifdef HAVE_UNIX_FD_PASSING _dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta); #endif _dbus_counter_notify (counter); _dbus_counter_unref (counter); } /** * Locks a message. Allows checking that applications don't keep a * reference to a message in the outgoing queue and change it * underneath us. Messages are locked when they enter the outgoing * queue (dbus_connection_send_message()), and the library complains * if the message is modified while locked. This function may also * called externally, for applications wrapping D-Bus in another protocol. * * @param message the message to lock. */ void dbus_message_lock (DBusMessage *message) { if (!message->locked) { _dbus_header_update_lengths (&message->header, _dbus_string_get_length (&message->body)); /* must have a signature if you have a body */ _dbus_assert (_dbus_string_get_length (&message->body) == 0 || dbus_message_get_signature (message) != NULL); message->locked = TRUE; } } static dbus_bool_t set_or_delete_string_field (DBusMessage *message, int field, int typecode, const char *value) { if (value == NULL) return _dbus_header_delete_field (&message->header, field); else return _dbus_header_set_field_basic (&message->header, field, typecode, &value); } #if 0 /* Probably we don't need to use this */ /** * Sets the signature of the message, i.e. the arguments in the * message payload. The signature includes only "in" arguments for * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from * what you might expect (it does not include the signature of the * entire C++-style method). * * The signature is a string made up of type codes such as * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also * the value of #DBUS_TYPE_INVALID). The macros such as * #DBUS_TYPE_INT32 evaluate to integers; to assemble a signature you * may find it useful to use the string forms, such as * #DBUS_TYPE_INT32_AS_STRING. * * An "unset" or #NULL signature is considered the same as an empty * signature. In fact dbus_message_get_signature() will never return * #NULL. * * @param message the message * @param signature the type signature or #NULL to unset * @returns #FALSE if no memory */ static dbus_bool_t _dbus_message_set_signature (DBusMessage *message, const char *signature) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (signature == NULL || _dbus_check_is_valid_signature (signature)); /* can't delete the signature if you have a message body */ _dbus_return_val_if_fail (_dbus_string_get_length (&message->body) == 0 || signature != NULL); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, signature); } #endif /* Message Cache * * We cache some DBusMessage to reduce the overhead of allocating * them. In my profiling this consistently made about an 8% * difference. It avoids the malloc for the message, the malloc for * the slot list, the malloc for the header string and body string, * and the associated free() calls. It does introduce another global * lock which could be a performance issue in certain cases. * * For the echo client/server the round trip time goes from around * .000077 to .000069 with the message cache on my laptop. The sysprof * change is as follows (numbers are cumulative percentage): * * with message cache implemented as array as it is now (0.000069 per): * new_empty_header 1.46 * mutex_lock 0.56 # i.e. _DBUS_LOCK(message_cache) * mutex_unlock 0.25 * self 0.41 * unref 2.24 * self 0.68 * list_clear 0.43 * mutex_lock 0.33 # i.e. _DBUS_LOCK(message_cache) * mutex_unlock 0.25 * * with message cache implemented as list (0.000070 per roundtrip): * new_empty_header 2.72 * list_pop_first 1.88 * unref 3.3 * list_prepend 1.63 * * without cache (0.000077 per roundtrip): * new_empty_header 6.7 * string_init_preallocated 3.43 * dbus_malloc 2.43 * dbus_malloc0 2.59 * * unref 4.02 * string_free 1.82 * dbus_free 1.63 * dbus_free 0.71 * * If you implement the message_cache with a list, the primary reason * it's slower is that you add another thread lock (on the DBusList * mempool). */ /** Avoid caching huge messages */ #define MAX_MESSAGE_SIZE_TO_CACHE 10 * _DBUS_ONE_KILOBYTE /** Avoid caching too many messages */ #define MAX_MESSAGE_CACHE_SIZE 5 /* Protected by _DBUS_LOCK (message_cache) */ static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE]; static int message_cache_count = 0; static dbus_bool_t message_cache_shutdown_registered = FALSE; static void dbus_message_cache_shutdown (void *data) { int i; if (!_DBUS_LOCK (message_cache)) _dbus_assert_not_reached ("we would have initialized global locks " "before registering a shutdown function"); i = 0; while (i < MAX_MESSAGE_CACHE_SIZE) { if (message_cache[i]) dbus_message_finalize (message_cache[i]); ++i; } message_cache_count = 0; message_cache_shutdown_registered = FALSE; _DBUS_UNLOCK (message_cache); } /** * Tries to get a message from the message cache. The retrieved * message will have junk in it, so it still needs to be cleared out * in dbus_message_new_empty_header() * * @returns the message, or #NULL if none cached */ static DBusMessage* dbus_message_get_cached (void) { DBusMessage *message; int i; message = NULL; if (!_DBUS_LOCK (message_cache)) { /* we'd have initialized global locks before caching anything, * so there can't be anything in the cache */ return NULL; } _dbus_assert (message_cache_count >= 0); if (message_cache_count == 0) { _DBUS_UNLOCK (message_cache); return NULL; } /* This is not necessarily true unless count > 0, and * message_cache is uninitialized until the shutdown is * registered */ _dbus_assert (message_cache_shutdown_registered); i = 0; while (i < MAX_MESSAGE_CACHE_SIZE) { if (message_cache[i]) { message = message_cache[i]; message_cache[i] = NULL; message_cache_count -= 1; break; } ++i; } _dbus_assert (message_cache_count >= 0); _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE); _dbus_assert (message != NULL); _dbus_assert (_dbus_atomic_get (&message->refcount) == 0); _dbus_assert (message->counters == NULL); _DBUS_UNLOCK (message_cache); return message; } #ifdef HAVE_UNIX_FD_PASSING static void close_unix_fds(int *fds, unsigned *n_fds) { DBusError e; unsigned int i; if (*n_fds <= 0) return; dbus_error_init(&e); for (i = 0; i < *n_fds; i++) { if (!_dbus_close(fds[i], &e)) { _dbus_warn("Failed to close file descriptor: %s\n", e.message); dbus_error_free(&e); } } *n_fds = 0; /* We don't free the array here, in case we can recycle it later */ } #endif static void free_counter (void *element, void *data) { DBusCounter *counter = element; DBusMessage *message = data; _dbus_counter_adjust_size (counter, - message->size_counter_delta); #ifdef HAVE_UNIX_FD_PASSING _dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta); #endif _dbus_counter_notify (counter); _dbus_counter_unref (counter); } /** * Tries to cache a message, otherwise finalize it. * * @param message the message */ static void dbus_message_cache_or_finalize (DBusMessage *message) { dbus_bool_t was_cached; int i; _dbus_assert (_dbus_atomic_get (&message->refcount) == 0); /* This calls application code and has to be done first thing * without holding the lock */ _dbus_data_slot_list_clear (&message->slot_list); _dbus_list_foreach (&message->counters, free_counter, message); _dbus_list_clear (&message->counters); #ifdef HAVE_UNIX_FD_PASSING close_unix_fds(message->unix_fds, &message->n_unix_fds); #endif was_cached = FALSE; if (!_DBUS_LOCK (message_cache)) { /* The only way to get a non-null message goes through * dbus_message_get_cached() which takes the lock. */ _dbus_assert_not_reached ("we would have initialized global locks " "the first time we constructed a message"); } if (!message_cache_shutdown_registered) { _dbus_assert (message_cache_count == 0); if (!_dbus_register_shutdown_func (dbus_message_cache_shutdown, NULL)) goto out; i = 0; while (i < MAX_MESSAGE_CACHE_SIZE) { message_cache[i] = NULL; ++i; } message_cache_shutdown_registered = TRUE; } _dbus_assert (message_cache_count >= 0); if (!_dbus_enable_message_cache ()) goto out; if ((_dbus_string_get_length (&message->header.data) + _dbus_string_get_length (&message->body)) > MAX_MESSAGE_SIZE_TO_CACHE) goto out; if (message_cache_count >= MAX_MESSAGE_CACHE_SIZE) goto out; /* Find empty slot */ i = 0; while (message_cache[i] != NULL) ++i; _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE); _dbus_assert (message_cache[i] == NULL); message_cache[i] = message; message_cache_count += 1; was_cached = TRUE; #ifndef DBUS_DISABLE_CHECKS message->in_cache = TRUE; #endif out: _dbus_assert (_dbus_atomic_get (&message->refcount) == 0); _DBUS_UNLOCK (message_cache); if (!was_cached) dbus_message_finalize (message); } #if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT) static dbus_bool_t _dbus_message_iter_check (DBusMessageRealIter *iter) { char byte_order; if (iter == NULL) { _dbus_warn_check_failed ("dbus message iterator is NULL\n"); return FALSE; } byte_order = _dbus_header_get_byte_order (&iter->message->header); if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER) { if (iter->u.reader.byte_order != byte_order) { _dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n"); return FALSE; } /* because we swap the message into compiler order when you init an iter */ _dbus_assert (iter->u.reader.byte_order == DBUS_COMPILER_BYTE_ORDER); } else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER) { if (iter->u.writer.byte_order != byte_order) { _dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n"); return FALSE; } /* because we swap the message into compiler order when you init an iter */ _dbus_assert (iter->u.writer.byte_order == DBUS_COMPILER_BYTE_ORDER); } else { _dbus_warn_check_failed ("dbus message iterator looks uninitialized or corrupted\n"); return FALSE; } if (iter->changed_stamp != iter->message->changed_stamp) { _dbus_warn_check_failed ("dbus message iterator invalid because the message has been modified (or perhaps the iterator is just uninitialized)\n"); return FALSE; } return TRUE; } #endif /* DBUS_ENABLE_CHECKS || DBUS_ENABLE_ASSERT */ /** * Implementation of the varargs arg-getting functions. * dbus_message_get_args() is the place to go for complete * documentation. * * @see dbus_message_get_args * @param iter the message iter * @param error error to be filled in * @param first_arg_type type of the first argument * @param var_args return location for first argument, followed by list of type/location pairs * @returns #FALSE if error was set */ dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter, DBusError *error, int first_arg_type, va_list var_args) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; int spec_type, msg_type, i, j; dbus_bool_t retval; va_list copy_args; _dbus_assert (_dbus_message_iter_check (real)); retval = FALSE; spec_type = first_arg_type; i = 0; /* copy var_args first, then we can do another iteration over it to * free memory and close unix fds if parse failed at some point. */ DBUS_VA_COPY (copy_args, var_args); while (spec_type != DBUS_TYPE_INVALID) { msg_type = dbus_message_iter_get_arg_type (iter); if (msg_type != spec_type) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Argument %d is specified to be of type \"%s\", but " "is actually of type \"%s\"\n", i, _dbus_type_to_string (spec_type), _dbus_type_to_string (msg_type)); goto out; } if (spec_type == DBUS_TYPE_UNIX_FD) { #ifdef HAVE_UNIX_FD_PASSING DBusBasicValue idx; int *pfd, nfd; pfd = va_arg (var_args, int*); _dbus_assert(pfd); _dbus_type_reader_read_basic(&real->u.reader, &idx); if (idx.u32 >= real->message->n_unix_fds) { dbus_set_error (error, DBUS_ERROR_INCONSISTENT_MESSAGE, "Message refers to file descriptor at index %i," "but has only %i descriptors attached.\n", idx.u32, real->message->n_unix_fds); goto out; } if ((nfd = _dbus_dup(real->message->unix_fds[idx.u32], error)) < 0) goto out; *pfd = nfd; #else dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Platform does not support file desciptor passing.\n"); goto out; #endif } else if (dbus_type_is_basic (spec_type)) { DBusBasicValue *ptr; ptr = va_arg (var_args, DBusBasicValue*); _dbus_assert (ptr != NULL); _dbus_type_reader_read_basic (&real->u.reader, ptr); } else if (spec_type == DBUS_TYPE_ARRAY) { int element_type; int spec_element_type; const DBusBasicValue **ptr; int *n_elements_p; DBusTypeReader array; spec_element_type = va_arg (var_args, int); element_type = _dbus_type_reader_get_element_type (&real->u.reader); if (spec_element_type != element_type) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Argument %d is specified to be an array of \"%s\", but " "is actually an array of \"%s\"\n", i, _dbus_type_to_string (spec_element_type), _dbus_type_to_string (element_type)); goto out; } if (dbus_type_is_fixed (spec_element_type) && element_type != DBUS_TYPE_UNIX_FD) { ptr = va_arg (var_args, const DBusBasicValue**); n_elements_p = va_arg (var_args, int*); _dbus_assert (ptr != NULL); _dbus_assert (n_elements_p != NULL); _dbus_type_reader_recurse (&real->u.reader, &array); _dbus_type_reader_read_fixed_multi (&array, (void *) ptr, n_elements_p); } else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type)) { char ***str_array_p; int n_elements; char **str_array; str_array_p = va_arg (var_args, char***); n_elements_p = va_arg (var_args, int*); _dbus_assert (str_array_p != NULL); _dbus_assert (n_elements_p != NULL); /* Count elements in the array */ _dbus_type_reader_recurse (&real->u.reader, &array); n_elements = 0; while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) { ++n_elements; _dbus_type_reader_next (&array); } str_array = dbus_new0 (char*, n_elements + 1); if (str_array == NULL) { _DBUS_SET_OOM (error); goto out; } /* Now go through and dup each string */ _dbus_type_reader_recurse (&real->u.reader, &array); j = 0; while (j < n_elements) { const char *s; _dbus_type_reader_read_basic (&array, (void *) &s); str_array[j] = _dbus_strdup (s); if (str_array[j] == NULL) { dbus_free_string_array (str_array); _DBUS_SET_OOM (error); goto out; } ++j; if (!_dbus_type_reader_next (&array)) _dbus_assert (j == n_elements); } _dbus_assert (_dbus_type_reader_get_current_type (&array) == DBUS_TYPE_INVALID); _dbus_assert (j == n_elements); _dbus_assert (str_array[j] == NULL); *str_array_p = str_array; *n_elements_p = n_elements; } #ifndef DBUS_DISABLE_CHECKS else { _dbus_warn ("you can't read arrays of container types (struct, variant, array) with %s for now\n", _DBUS_FUNCTION_NAME); goto out; } #endif } #ifndef DBUS_DISABLE_CHECKS else { _dbus_warn ("you can only read arrays and basic types with %s for now\n", _DBUS_FUNCTION_NAME); goto out; } #endif /* how many arguments already handled */ i++; spec_type = va_arg (var_args, int); if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Message has only %d arguments, but more were expected", i); goto out; } } retval = TRUE; out: /* there may memory or unix fd leak in the above iteration if parse failed. * so we have another iteration over copy_args to free memory and close * unix fds. */ if (!retval) { spec_type = first_arg_type; j = 0; while (j < i) { if (spec_type == DBUS_TYPE_UNIX_FD) { #ifdef HAVE_UNIX_FD_PASSING int *pfd; pfd = va_arg (copy_args, int *); _dbus_assert(pfd); if (*pfd >= 0) { _dbus_close (*pfd, NULL); *pfd = -1; } #endif } else if (dbus_type_is_basic (spec_type)) { /* move the index forward */ va_arg (copy_args, DBusBasicValue *); } else if (spec_type == DBUS_TYPE_ARRAY) { int spec_element_type; spec_element_type = va_arg (copy_args, int); if (dbus_type_is_fixed (spec_element_type)) { /* move the index forward */ va_arg (copy_args, const DBusBasicValue **); va_arg (copy_args, int *); } else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type)) { char ***str_array_p; str_array_p = va_arg (copy_args, char ***); /* move the index forward */ va_arg (copy_args, int *); _dbus_assert (str_array_p != NULL); dbus_free_string_array (*str_array_p); *str_array_p = NULL; } } spec_type = va_arg (copy_args, int); j++; } } va_end (copy_args); return retval; } /** @} */ /** * @defgroup DBusMessage DBusMessage * @ingroup DBus * @brief Message to be sent or received over a #DBusConnection. * * A DBusMessage is the most basic unit of communication over a * DBusConnection. A DBusConnection represents a stream of messages * received from a remote application, and a stream of messages * sent to a remote application. * * A message has a message type, returned from * dbus_message_get_type(). This indicates whether the message is a * method call, a reply to a method call, a signal, or an error reply. * * A message has header fields such as the sender, destination, method * or signal name, and so forth. DBusMessage has accessor functions for * these, such as dbus_message_get_member(). * * Convenience functions dbus_message_is_method_call(), dbus_message_is_signal(), * and dbus_message_is_error() check several header fields at once and are * slightly more efficient than checking the header fields with individual * accessor functions. * * Finally, a message has arguments. The number and types of arguments * are in the message's signature header field (accessed with * dbus_message_get_signature()). Simple argument values are usually * retrieved with dbus_message_get_args() but more complex values such * as structs may require the use of #DBusMessageIter. * * The D-Bus specification goes into some more detail about header fields and * message types. * * @{ */ /** * @typedef DBusMessage * * Opaque data type representing a message received from or to be * sent to another application. */ /** * Returns the serial of a message or 0 if none has been specified. * The message's serial number is provided by the application sending * the message and is used to identify replies to this message. * * All messages received on a connection will have a serial provided * by the remote application. * * For messages you're sending, dbus_connection_send() will assign a * serial and return it to you. * * @param message the message * @returns the serial */ dbus_uint32_t dbus_message_get_serial (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, 0); return _dbus_header_get_serial (&message->header); } /** * Sets the reply serial of a message (the serial of the message this * is a reply to). * * @param message the message * @param reply_serial the serial we're replying to * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message, dbus_uint32_t reply_serial) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (reply_serial != 0, FALSE); /* 0 is invalid */ return _dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32, &reply_serial); } /** * Returns the serial that the message is a reply to or 0 if none. * * @param message the message * @returns the reply serial */ dbus_uint32_t dbus_message_get_reply_serial (DBusMessage *message) { dbus_uint32_t v_UINT32; _dbus_return_val_if_fail (message != NULL, 0); if (_dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32, &v_UINT32)) return v_UINT32; else return 0; } static void dbus_message_finalize (DBusMessage *message) { _dbus_assert (_dbus_atomic_get (&message->refcount) == 0); /* This calls application callbacks! */ _dbus_data_slot_list_free (&message->slot_list); _dbus_list_foreach (&message->counters, free_counter, message); _dbus_list_clear (&message->counters); _dbus_header_free (&message->header); _dbus_string_free (&message->body); #ifdef HAVE_UNIX_FD_PASSING close_unix_fds(message->unix_fds, &message->n_unix_fds); dbus_free(message->unix_fds); #endif _dbus_assert (_dbus_atomic_get (&message->refcount) == 0); dbus_free (message); } static DBusMessage* dbus_message_new_empty_header (void) { DBusMessage *message; dbus_bool_t from_cache; message = dbus_message_get_cached (); if (message != NULL) { from_cache = TRUE; } else { from_cache = FALSE; message = dbus_new0 (DBusMessage, 1); if (message == NULL) return NULL; #ifndef DBUS_DISABLE_CHECKS message->generation = _dbus_current_generation; #endif #ifdef HAVE_UNIX_FD_PASSING message->unix_fds = NULL; message->n_unix_fds_allocated = 0; #endif } _dbus_atomic_inc (&message->refcount); _dbus_message_trace_ref (message, 0, 1, "new_empty_header"); message->locked = FALSE; #ifndef DBUS_DISABLE_CHECKS message->in_cache = FALSE; #endif message->counters = NULL; message->size_counter_delta = 0; message->changed_stamp = 0; #ifdef HAVE_UNIX_FD_PASSING message->n_unix_fds = 0; message->n_unix_fds_allocated = 0; message->unix_fd_counter_delta = 0; #endif if (!from_cache) _dbus_data_slot_list_init (&message->slot_list); if (from_cache) { _dbus_header_reinit (&message->header); _dbus_string_set_length (&message->body, 0); } else { if (!_dbus_header_init (&message->header)) { dbus_free (message); return NULL; } if (!_dbus_string_init_preallocated (&message->body, 32)) { _dbus_header_free (&message->header); dbus_free (message); return NULL; } } return message; } /** * Constructs a new message of the given message type. * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL, * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth. * * Usually you want to use dbus_message_new_method_call(), * dbus_message_new_method_return(), dbus_message_new_signal(), * or dbus_message_new_error() instead. * * @param message_type type of message * @returns new message or #NULL if no memory */ DBusMessage* dbus_message_new (int message_type) { DBusMessage *message; _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL); message = dbus_message_new_empty_header (); if (message == NULL) return NULL; if (!_dbus_header_create (&message->header, DBUS_COMPILER_BYTE_ORDER, message_type, NULL, NULL, NULL, NULL, NULL)) { dbus_message_unref (message); return NULL; } return message; } /** * Constructs a new message to invoke a method on a remote * object. Returns #NULL if memory can't be allocated for the * message. The destination may be #NULL in which case no destination * is set; this is appropriate when using D-Bus in a peer-to-peer * context (no message bus). The interface may be #NULL, which means * that if multiple methods with the given name exist it is undefined * which one will be invoked. * * The path and method names may not be #NULL. * * Destination, path, interface, and method name can't contain * any invalid characters (see the D-Bus specification). * * @param destination name that the message should be sent to or #NULL * @param path object path the message should be sent to * @param iface interface to invoke method on, or #NULL * @param method method to invoke * * @returns a new DBusMessage, free with dbus_message_unref() */ DBusMessage* dbus_message_new_method_call (const char *destination, const char *path, const char *iface, const char *method) { DBusMessage *message; _dbus_return_val_if_fail (path != NULL, NULL); _dbus_return_val_if_fail (method != NULL, NULL); _dbus_return_val_if_fail (destination == NULL || _dbus_check_is_valid_bus_name (destination), NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); _dbus_return_val_if_fail (iface == NULL || _dbus_check_is_valid_interface (iface), NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL); message = dbus_message_new_empty_header (); if (message == NULL) return NULL; if (!_dbus_header_create (&message->header, DBUS_COMPILER_BYTE_ORDER, DBUS_MESSAGE_TYPE_METHOD_CALL, destination, path, iface, method, NULL)) { dbus_message_unref (message); return NULL; } return message; } /** * Constructs a message that is a reply to a method call. Returns * #NULL if memory can't be allocated for the message. * * @param method_call the message being replied to * @returns a new DBusMessage, free with dbus_message_unref() */ DBusMessage* dbus_message_new_method_return (DBusMessage *method_call) { DBusMessage *message; const char *sender; _dbus_return_val_if_fail (method_call != NULL, NULL); sender = dbus_message_get_sender (method_call); /* sender is allowed to be null here in peer-to-peer case */ message = dbus_message_new_empty_header (); if (message == NULL) return NULL; if (!_dbus_header_create (&message->header, DBUS_COMPILER_BYTE_ORDER, DBUS_MESSAGE_TYPE_METHOD_RETURN, sender, NULL, NULL, NULL, NULL)) { dbus_message_unref (message); return NULL; } dbus_message_set_no_reply (message, TRUE); if (!dbus_message_set_reply_serial (message, dbus_message_get_serial (method_call))) { dbus_message_unref (message); return NULL; } return message; } /** * Constructs a new message representing a signal emission. Returns * #NULL if memory can't be allocated for the message. A signal is * identified by its originating object path, interface, and the name * of the signal. * * Path, interface, and signal name must all be valid (the D-Bus * specification defines the syntax of these fields). * * @param path the path to the object emitting the signal * @param iface the interface the signal is emitted from * @param name name of the signal * @returns a new DBusMessage, free with dbus_message_unref() */ DBusMessage* dbus_message_new_signal (const char *path, const char *iface, const char *name) { DBusMessage *message; _dbus_return_val_if_fail (path != NULL, NULL); _dbus_return_val_if_fail (iface != NULL, NULL); _dbus_return_val_if_fail (name != NULL, NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_interface (iface), NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL); message = dbus_message_new_empty_header (); if (message == NULL) return NULL; if (!_dbus_header_create (&message->header, DBUS_COMPILER_BYTE_ORDER, DBUS_MESSAGE_TYPE_SIGNAL, NULL, path, iface, name, NULL)) { dbus_message_unref (message); return NULL; } dbus_message_set_no_reply (message, TRUE); return message; } /** * Creates a new message that is an error reply to another message. * Error replies are most common in response to method calls, but * can be returned in reply to any message. * * The error name must be a valid error name according to the syntax * given in the D-Bus specification. If you don't want to make * up an error name just use #DBUS_ERROR_FAILED. * * @param reply_to the message we're replying to * @param error_name the error name * @param error_message the error message string (or #NULL for none, but please give a message) * @returns a new error message object, free with dbus_message_unref() */ DBusMessage* dbus_message_new_error (DBusMessage *reply_to, const char *error_name, const char *error_message) { DBusMessage *message; const char *sender; DBusMessageIter iter; _dbus_return_val_if_fail (reply_to != NULL, NULL); _dbus_return_val_if_fail (error_name != NULL, NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); sender = dbus_message_get_sender (reply_to); /* sender may be NULL for non-message-bus case or * when the message bus is dealing with an unregistered * connection. */ message = dbus_message_new_empty_header (); if (message == NULL) return NULL; if (!_dbus_header_create (&message->header, DBUS_COMPILER_BYTE_ORDER, DBUS_MESSAGE_TYPE_ERROR, sender, NULL, NULL, NULL, error_name)) { dbus_message_unref (message); return NULL; } dbus_message_set_no_reply (message, TRUE); if (!dbus_message_set_reply_serial (message, dbus_message_get_serial (reply_to))) { dbus_message_unref (message); return NULL; } if (error_message != NULL) { dbus_message_iter_init_append (message, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &error_message)) { dbus_message_unref (message); return NULL; } } return message; } /** * Creates a new message that is an error reply to another message, allowing * you to use printf formatting. * * See dbus_message_new_error() for details - this function is the same * aside from the printf formatting. * * @todo add _DBUS_GNUC_PRINTF to this (requires moving _DBUS_GNUC_PRINTF to * public header, see DBUS_DEPRECATED for an example) * * @param reply_to the original message * @param error_name the error name * @param error_format the error message format as with printf * @param ... format string arguments * @returns a new error message */ DBusMessage* dbus_message_new_error_printf (DBusMessage *reply_to, const char *error_name, const char *error_format, ...) { va_list args; DBusString str; DBusMessage *message; _dbus_return_val_if_fail (reply_to != NULL, NULL); _dbus_return_val_if_fail (error_name != NULL, NULL); _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); if (!_dbus_string_init (&str)) return NULL; va_start (args, error_format); if (_dbus_string_append_printf_valist (&str, error_format, args)) message = dbus_message_new_error (reply_to, error_name, _dbus_string_get_const_data (&str)); else message = NULL; _dbus_string_free (&str); va_end (args); return message; } /** * Creates a new message that is an exact replica of the message * specified, except that its refcount is set to 1, its message serial * is reset to 0, and if the original message was "locked" (in the * outgoing message queue and thus not modifiable) the new message * will not be locked. * * @todo This function can't be used in programs that try to recover from OOM errors. * * @param message the message * @returns the new message.or #NULL if not enough memory or Unix file descriptors (in case the message to copy includes Unix file descriptors) can be allocated. */ DBusMessage * dbus_message_copy (const DBusMessage *message) { DBusMessage *retval; _dbus_return_val_if_fail (message != NULL, NULL); retval = dbus_new0 (DBusMessage, 1); if (retval == NULL) return NULL; _dbus_atomic_inc (&retval->refcount); retval->locked = FALSE; #ifndef DBUS_DISABLE_CHECKS retval->generation = message->generation; #endif if (!_dbus_header_copy (&message->header, &retval->header)) { dbus_free (retval); return NULL; } if (!_dbus_string_init_preallocated (&retval->body, _dbus_string_get_length (&message->body))) { _dbus_header_free (&retval->header); dbus_free (retval); return NULL; } if (!_dbus_string_copy (&message->body, 0, &retval->body, 0)) goto failed_copy; #ifdef HAVE_UNIX_FD_PASSING retval->unix_fds = dbus_new(int, message->n_unix_fds); if (retval->unix_fds == NULL && message->n_unix_fds > 0) goto failed_copy; retval->n_unix_fds_allocated = message->n_unix_fds; for (retval->n_unix_fds = 0; retval->n_unix_fds < message->n_unix_fds; retval->n_unix_fds++) { retval->unix_fds[retval->n_unix_fds] = _dbus_dup(message->unix_fds[retval->n_unix_fds], NULL); if (retval->unix_fds[retval->n_unix_fds] < 0) goto failed_copy; } #endif _dbus_message_trace_ref (retval, 0, 1, "copy"); return retval; failed_copy: _dbus_header_free (&retval->header); _dbus_string_free (&retval->body); #ifdef HAVE_UNIX_FD_PASSING close_unix_fds(retval->unix_fds, &retval->n_unix_fds); dbus_free(retval->unix_fds); #endif dbus_free (retval); return NULL; } /** * Increments the reference count of a DBusMessage. * * @param message the message * @returns the message * @see dbus_message_unref */ DBusMessage * dbus_message_ref (DBusMessage *message) { dbus_int32_t old_refcount; _dbus_return_val_if_fail (message != NULL, NULL); _dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL); _dbus_return_val_if_fail (!message->in_cache, NULL); old_refcount = _dbus_atomic_inc (&message->refcount); _dbus_assert (old_refcount >= 1); _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref"); return message; } /** * Decrements the reference count of a DBusMessage, freeing the * message if the count reaches 0. * * @param message the message * @see dbus_message_ref */ void dbus_message_unref (DBusMessage *message) { dbus_int32_t old_refcount; _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (message->generation == _dbus_current_generation); _dbus_return_if_fail (!message->in_cache); old_refcount = _dbus_atomic_dec (&message->refcount); _dbus_assert (old_refcount >= 1); _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref"); if (old_refcount == 1) { /* Calls application callbacks! */ dbus_message_cache_or_finalize (message); } } /** * Gets the type of a message. Types include * #DBUS_MESSAGE_TYPE_METHOD_CALL, #DBUS_MESSAGE_TYPE_METHOD_RETURN, * #DBUS_MESSAGE_TYPE_ERROR, #DBUS_MESSAGE_TYPE_SIGNAL, but other * types are allowed and all code must silently ignore messages of * unknown type. #DBUS_MESSAGE_TYPE_INVALID will never be returned. * * @param message the message * @returns the type of the message */ int dbus_message_get_type (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, DBUS_MESSAGE_TYPE_INVALID); return _dbus_header_get_message_type (&message->header); } /** * Appends fields to a message given a variable argument list. The * variable argument list should contain the type of each argument * followed by the value to append. Appendable types are basic types, * and arrays of fixed-length basic types (except arrays of Unix file * descriptors). To append variable-length basic types, or any more * complex value, you have to use an iterator rather than this * function. * * To append a basic type, specify its type code followed by the * address of the value. For example: * * @code * * dbus_int32_t v_INT32 = 42; * const char *v_STRING = "Hello World"; * dbus_message_append_args (message, * DBUS_TYPE_INT32, &v_INT32, * DBUS_TYPE_STRING, &v_STRING, * DBUS_TYPE_INVALID); * @endcode * * To append an array of fixed-length basic types (except Unix file * descriptors), pass in the DBUS_TYPE_ARRAY typecode, the element * typecode, the address of the array pointer, and a 32-bit integer * giving the number of elements in the array. So for example: @code * const dbus_int32_t array[] = { 1, 2, 3 }; const dbus_int32_t * *v_ARRAY = array; dbus_message_append_args (message, * DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3, DBUS_TYPE_INVALID); * @endcode * * This function does not support arrays of Unix file descriptors. If * you need those you need to manually recurse into the array. * * For Unix file descriptors this function will internally duplicate * the descriptor you passed in. Hence you may close the descriptor * immediately after this call. * * @warning in C, given "int array[]", "&array == array" (the * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). * So if you're using an array instead of a pointer you have to create * a pointer variable, assign the array to it, then take the address * of the pointer variable. For strings it works to write * const char *array = "Hello" and then use &array though. * * The last argument to this function must be #DBUS_TYPE_INVALID, * marking the end of the argument list. If you don't do this * then libdbus won't know to stop and will read invalid memory. * * String/signature/path arrays should be passed in as "const char*** * address_of_array" and "int n_elements" * * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays * * @todo If this fails due to lack of memory, the message is hosed and * you have to start over building the whole message. * * @param message the message * @param first_arg_type type of the first argument * @param ... value of first argument, list of additional type-value pairs * @returns #TRUE on success */ dbus_bool_t dbus_message_append_args (DBusMessage *message, int first_arg_type, ...) { dbus_bool_t retval; va_list var_args; _dbus_return_val_if_fail (message != NULL, FALSE); va_start (var_args, first_arg_type); retval = dbus_message_append_args_valist (message, first_arg_type, var_args); va_end (var_args); return retval; } /** * Like dbus_message_append_args() but takes a va_list for use by language bindings. * * @todo for now, if this function fails due to OOM it will leave * the message half-written and you have to discard the message * and start over. * * @see dbus_message_append_args. * @param message the message * @param first_arg_type type of first argument * @param var_args value of first argument, then list of type/value pairs * @returns #TRUE on success */ dbus_bool_t dbus_message_append_args_valist (DBusMessage *message, int first_arg_type, va_list var_args) { int type; DBusMessageIter iter; _dbus_return_val_if_fail (message != NULL, FALSE); type = first_arg_type; dbus_message_iter_init_append (message, &iter); while (type != DBUS_TYPE_INVALID) { if (dbus_type_is_basic (type)) { const DBusBasicValue *value; value = va_arg (var_args, const DBusBasicValue*); if (!dbus_message_iter_append_basic (&iter, type, value)) goto failed; } else if (type == DBUS_TYPE_ARRAY) { int element_type; DBusMessageIter array; char buf[2]; element_type = va_arg (var_args, int); buf[0] = element_type; buf[1] = '\0'; if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, buf, &array)) goto failed; if (dbus_type_is_fixed (element_type) && element_type != DBUS_TYPE_UNIX_FD) { const DBusBasicValue **value; int n_elements; value = va_arg (var_args, const DBusBasicValue**); n_elements = va_arg (var_args, int); if (!dbus_message_iter_append_fixed_array (&array, element_type, value, n_elements)) { dbus_message_iter_abandon_container (&iter, &array); goto failed; } } else if (_DBUS_TYPE_IS_STRINGLIKE (element_type)) { const char ***value_p; const char **value; int n_elements; int i; value_p = va_arg (var_args, const char***); n_elements = va_arg (var_args, int); value = *value_p; i = 0; while (i < n_elements) { if (!dbus_message_iter_append_basic (&array, element_type, &value[i])) { dbus_message_iter_abandon_container (&iter, &array); goto failed; } ++i; } } else { _dbus_warn ("arrays of %s can't be appended with %s for now\n", _dbus_type_to_string (element_type), _DBUS_FUNCTION_NAME); goto failed; } if (!dbus_message_iter_close_container (&iter, &array)) goto failed; } #ifndef DBUS_DISABLE_CHECKS else { _dbus_warn ("type %s isn't supported yet in %s\n", _dbus_type_to_string (type), _DBUS_FUNCTION_NAME); goto failed; } #endif type = va_arg (var_args, int); } return TRUE; failed: return FALSE; } /** * Gets arguments from a message given a variable argument list. The * supported types include those supported by * dbus_message_append_args(); that is, basic types and arrays of * fixed-length basic types. The arguments are the same as they would * be for dbus_message_iter_get_basic() or * dbus_message_iter_get_fixed_array(). * * In addition to those types, arrays of string, object path, and * signature are supported; but these are returned as allocated memory * and must be freed with dbus_free_string_array(), while the other * types are returned as const references. To get a string array * pass in "char ***array_location" and "int *n_elements". * * Similar to dbus_message_get_fixed_array() this function does not * support arrays of type DBUS_TYPE_UNIX_FD. If you need to parse * messages with arrays of Unix file descriptors you need to recurse * into the array manually. * * Unix file descriptors that are read with this function will have * the FD_CLOEXEC flag set. If you need them without this flag set, * make sure to unset it with fcntl(). * * The variable argument list should contain the type of the argument * followed by a pointer to where the value should be stored. The list * is terminated with #DBUS_TYPE_INVALID. * * Except for string arrays, the returned values are constant; do not * free them. They point into the #DBusMessage. * * If the requested arguments are not present, or do not have the * requested types, then an error will be set. * * If more arguments than requested are present, the requested * arguments are returned and the extra arguments are ignored. * * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays * * @param message the message * @param error error to be filled in on failure * @param first_arg_type the first argument type * @param ... location for first argument value, then list of type-location pairs * @returns #FALSE if the error was set */ dbus_bool_t dbus_message_get_args (DBusMessage *message, DBusError *error, int first_arg_type, ...) { dbus_bool_t retval; va_list var_args; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); va_start (var_args, first_arg_type); retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args); va_end (var_args); return retval; } /** * Like dbus_message_get_args but takes a va_list for use by language bindings. * * @see dbus_message_get_args * @param message the message * @param error error to be filled in * @param first_arg_type type of the first argument * @param var_args return location for first argument, followed by list of type/location pairs * @returns #FALSE if error was set */ dbus_bool_t dbus_message_get_args_valist (DBusMessage *message, DBusError *error, int first_arg_type, va_list var_args) { DBusMessageIter iter; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); dbus_message_iter_init (message, &iter); return _dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args); } static void _dbus_message_iter_init_common (DBusMessage *message, DBusMessageRealIter *real, int iter_type) { _DBUS_STATIC_ASSERT (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); /* Since the iterator will read or write who-knows-what from the * message, we need to get in the right byte order */ ensure_byte_order (message); real->message = message; real->changed_stamp = message->changed_stamp; real->iter_type = iter_type; real->sig_refcount = 0; } /** * Initializes a #DBusMessageIter for reading the arguments of the * message passed in. * * When possible, dbus_message_get_args() is much more convenient. * Some types of argument can only be read with #DBusMessageIter * however. * * The easiest way to iterate is like this: * @code * dbus_message_iter_init (message, &iter); * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) * dbus_message_iter_next (&iter); * @endcode * * #DBusMessageIter contains no allocated memory; it need not be * freed, and can be copied by assignment or memcpy(). * * @param message the message * @param iter pointer to an iterator to initialize * @returns #FALSE if the message has no arguments */ dbus_bool_t dbus_message_iter_init (DBusMessage *message, DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; const DBusString *type_str; int type_pos; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (iter != NULL, FALSE); get_const_signature (&message->header, &type_str, &type_pos); _dbus_message_iter_init_common (message, real, DBUS_MESSAGE_ITER_TYPE_READER); _dbus_type_reader_init (&real->u.reader, _dbus_header_get_byte_order (&message->header), type_str, type_pos, &message->body, 0); return _dbus_type_reader_get_current_type (&real->u.reader) != DBUS_TYPE_INVALID; } /** * Checks if an iterator has any more fields. * * @param iter the message iter * @returns #TRUE if there are more fields following */ dbus_bool_t dbus_message_iter_has_next (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); return _dbus_type_reader_has_next (&real->u.reader); } /** * Moves the iterator to the next field, if any. If there's no next * field, returns #FALSE. If the iterator moves forward, returns * #TRUE. * * @param iter the message iter * @returns #TRUE if the iterator was moved to the next field */ dbus_bool_t dbus_message_iter_next (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); return _dbus_type_reader_next (&real->u.reader); } /** * Returns the argument type of the argument that the message iterator * points to. If the iterator is at the end of the message, returns * #DBUS_TYPE_INVALID. You can thus write a loop as follows: * * @code * dbus_message_iter_init (message, &iter); * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) * dbus_message_iter_next (&iter); * @endcode * * @param iter the message iter * @returns the argument type */ int dbus_message_iter_get_arg_type (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); return _dbus_type_reader_get_current_type (&real->u.reader); } /** * Returns the element type of the array that the message iterator * points to. Note that you need to check that the iterator points to * an array prior to using this function. * * @param iter the message iter * @returns the array element type */ int dbus_message_iter_get_element_type (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, DBUS_TYPE_INVALID); _dbus_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID); return _dbus_type_reader_get_element_type (&real->u.reader); } /** * Recurses into a container value when reading values from a message, * initializing a sub-iterator to use for traversing the child values * of the container. * * Note that this recurses into a value, not a type, so you can only * recurse if the value exists. The main implication of this is that * if you have for example an empty array of array of int32, you can * recurse into the outermost array, but it will have no values, so * you won't be able to recurse further. There's no array of int32 to * recurse into. * * If a container is an array of fixed-length types (except Unix file * descriptors), it is much more efficient to use * dbus_message_iter_get_fixed_array() to get the whole array in one * shot, rather than individually walking over the array elements. * * Be sure you have somehow checked that * dbus_message_iter_get_arg_type() matches the type you are expecting * to recurse into. Results of this function are undefined if there is * no container to recurse into at the current iterator position. * * @param iter the message iterator * @param sub the sub-iterator to initialize */ void dbus_message_iter_recurse (DBusMessageIter *iter, DBusMessageIter *sub) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; _dbus_return_if_fail (_dbus_message_iter_check (real)); _dbus_return_if_fail (sub != NULL); *real_sub = *real; _dbus_type_reader_recurse (&real->u.reader, &real_sub->u.reader); } /** * Returns the current signature of a message iterator. This * is useful primarily for dealing with variants; one can * recurse into a variant and determine the signature of * the variant's value. * * The returned string must be freed with dbus_free(). * * @param iter the message iterator * @returns the contained signature, or NULL if out of memory */ char * dbus_message_iter_get_signature (DBusMessageIter *iter) { const DBusString *sig; DBusString retstr; char *ret; int start, len; DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), NULL); if (!_dbus_string_init (&retstr)) return NULL; _dbus_type_reader_get_signature (&real->u.reader, &sig, &start, &len); if (!_dbus_string_append_len (&retstr, _dbus_string_get_const_data (sig) + start, len)) return NULL; if (!_dbus_string_steal_data (&retstr, &ret)) return NULL; _dbus_string_free (&retstr); return ret; } /** * Reads a basic-typed value from the message iterator. * Basic types are the non-containers such as integer and string. * * The value argument should be the address of a location to store * the returned value. So for int32 it should be a "dbus_int32_t*" * and for string a "const char**". The returned value is * by reference and should not be freed. * * This call duplicates Unix file descriptors when reading them. It is * your job to close them when you don't need them anymore. * * Unix file descriptors that are read with this function will have * the FD_CLOEXEC flag set. If you need them without this flag set, * make sure to unset it with fcntl(). * * Be sure you have somehow checked that * dbus_message_iter_get_arg_type() matches the type you are * expecting, or you'll crash when you try to use an integer as a * string or something. * * To read any container type (array, struct, dict) you will need to * recurse into the container with dbus_message_iter_recurse(). If * the container is an array of fixed-length values (except Unix file * descriptors), you can get all the array elements at once with * dbus_message_iter_get_fixed_array(). Otherwise, you have to iterate * over the container's contents one value at a time. * * All basic-typed values are guaranteed to fit in a #DBusBasicValue, * so in versions of libdbus that have that type, you can write code like this: * * @code * DBusBasicValue value; * int type; * dbus_message_iter_get_basic (&read_iter, &value); * type = dbus_message_iter_get_arg_type (&read_iter); * dbus_message_iter_append_basic (&write_iter, type, &value); * @endcode * * (All D-Bus basic types are either numeric and 8 bytes or smaller, or * behave like a string; so in older versions of libdbus, DBusBasicValue * can be replaced with union { char *string; unsigned char bytes[8]; }, * for instance.) * * @param iter the iterator * @param value location to store the value */ void dbus_message_iter_get_basic (DBusMessageIter *iter, void *value) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_if_fail (_dbus_message_iter_check (real)); _dbus_return_if_fail (value != NULL); if (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_UNIX_FD) { #ifdef HAVE_UNIX_FD_PASSING DBusBasicValue idx; _dbus_type_reader_read_basic(&real->u.reader, &idx); if (idx.u32 >= real->message->n_unix_fds) { /* Hmm, we cannot really signal an error here, so let's make sure to return an invalid fd. */ *((int*) value) = -1; return; } *((int*) value) = _dbus_dup(real->message->unix_fds[idx.u32], NULL); #else *((int*) value) = -1; #endif } else { _dbus_type_reader_read_basic (&real->u.reader, value); } } /** * Returns the number of elements in the array-typed value pointed * to by the iterator. * Note that this function is O(1) for arrays of fixed-size types * but O(n) for arrays of variable-length types such as strings, * so it may be a bad idea to use it. * * @param iter the iterator * @returns the number of elements in the array */ int dbus_message_iter_get_element_count (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; DBusTypeReader array; int element_type; int n_elements = 0; _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0); _dbus_return_val_if_fail (_dbus_type_reader_get_current_type (&real->u.reader) == DBUS_TYPE_ARRAY, 0); element_type = _dbus_type_reader_get_element_type (&real->u.reader); _dbus_type_reader_recurse (&real->u.reader, &array); if (dbus_type_is_fixed (element_type)) { int alignment = _dbus_type_get_alignment (element_type); int total_len = _dbus_type_reader_get_array_length (&array); n_elements = total_len / alignment; } else { while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) { ++n_elements; _dbus_type_reader_next (&array); } } return n_elements; } /** * Returns the number of bytes in the array as marshaled in the wire * protocol. The iterator must currently be inside an array-typed * value. * * This function is deprecated on the grounds that it is stupid. Why * would you want to know how many bytes are in the array as marshaled * in the wire protocol? Use dbus_message_iter_get_element_count() instead. * * @param iter the iterator * @returns the number of bytes in the array */ int dbus_message_iter_get_array_len (DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0); return _dbus_type_reader_get_array_length (&real->u.reader); } /** * Reads a block of fixed-length values from the message iterator. * Fixed-length values are those basic types that are not string-like, * such as integers, bool, double. The returned block will be from the * current position in the array until the end of the array. * * There is one exception here: although DBUS_TYPE_UNIX_FD is * considered a 'fixed' type arrays of this type may not be read with * this function. * * The message iter should be "in" the array (that is, you recurse into the * array, and then you call dbus_message_iter_get_fixed_array() on the * "sub-iterator" created by dbus_message_iter_recurse()). * * The value argument should be the address of a location to store the * returned array. So for int32 it should be a "const dbus_int32_t**" * The returned value is by reference and should not be freed. * * This function should only be used if dbus_type_is_fixed() returns * #TRUE for the element type. * * If an array's elements are not fixed in size, you have to recurse * into the array with dbus_message_iter_recurse() and read the * elements one by one. * * Because the array is not copied, this function runs in constant * time and is fast; it's much preferred over walking the entire array * with an iterator. (However, you can always use * dbus_message_iter_recurse(), even for fixed-length types; * dbus_message_iter_get_fixed_array() is just an optimization.) * * @param iter the iterator * @param value location to store the block * @param n_elements number of elements in the block */ void dbus_message_iter_get_fixed_array (DBusMessageIter *iter, void *value, int *n_elements) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; #ifndef DBUS_DISABLE_CHECKS int subtype = _dbus_type_reader_get_current_type(&real->u.reader); _dbus_return_if_fail (_dbus_message_iter_check (real)); _dbus_return_if_fail (value != NULL); _dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) || (dbus_type_is_fixed (subtype) && subtype != DBUS_TYPE_UNIX_FD)); #endif _dbus_type_reader_read_fixed_multi (&real->u.reader, value, n_elements); } /** * Initializes a #DBusMessageIter for appending arguments to the end * of a message. * * @todo If appending any of the arguments fails due to lack of * memory, the message is hosed and you have to start over building * the whole message. * * @param message the message * @param iter pointer to an iterator to initialize */ void dbus_message_iter_init_append (DBusMessage *message, DBusMessageIter *iter) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (iter != NULL); _dbus_message_iter_init_common (message, real, DBUS_MESSAGE_ITER_TYPE_WRITER); /* We create the signature string and point iterators at it "on demand" * when a value is actually appended. That means that init() never fails * due to OOM. */ _dbus_type_writer_init_types_delayed (&real->u.writer, _dbus_header_get_byte_order (&message->header), &message->body, _dbus_string_get_length (&message->body)); } /** * Creates a temporary signature string containing the current * signature, stores it in the iterator, and points the iterator to * the end of it. Used any time we write to the message. * * @param real an iterator without a type_str * @returns #FALSE if no memory */ static dbus_bool_t _dbus_message_iter_open_signature (DBusMessageRealIter *real) { DBusString *str; const DBusString *current_sig; int current_sig_pos; _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); if (real->u.writer.type_str != NULL) { _dbus_assert (real->sig_refcount > 0); real->sig_refcount += 1; return TRUE; } str = dbus_new (DBusString, 1); if (str == NULL) return FALSE; if (!_dbus_header_get_field_raw (&real->message->header, DBUS_HEADER_FIELD_SIGNATURE, ¤t_sig, ¤t_sig_pos)) current_sig = NULL; if (current_sig) { int current_len; current_len = _dbus_string_get_byte (current_sig, current_sig_pos); current_sig_pos += 1; /* move on to sig data */ if (!_dbus_string_init_preallocated (str, current_len + 4)) { dbus_free (str); return FALSE; } if (!_dbus_string_copy_len (current_sig, current_sig_pos, current_len, str, 0)) { _dbus_string_free (str); dbus_free (str); return FALSE; } } else { if (!_dbus_string_init_preallocated (str, 4)) { dbus_free (str); return FALSE; } } real->sig_refcount = 1; _dbus_type_writer_add_types (&real->u.writer, str, _dbus_string_get_length (str)); return TRUE; } /** * Sets the new signature as the message signature, frees the * signature string, and marks the iterator as not having a type_str * anymore. Frees the signature even if it fails, so you can't * really recover from failure. Kinda busted. * * @param real an iterator without a type_str * @returns #FALSE if no memory */ static dbus_bool_t _dbus_message_iter_close_signature (DBusMessageRealIter *real) { DBusString *str; const char *v_STRING; dbus_bool_t retval; _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); _dbus_assert (real->u.writer.type_str != NULL); _dbus_assert (real->sig_refcount > 0); real->sig_refcount -= 1; if (real->sig_refcount > 0) return TRUE; _dbus_assert (real->sig_refcount == 0); retval = TRUE; str = real->u.writer.type_str; v_STRING = _dbus_string_get_const_data (str); if (!_dbus_header_set_field_basic (&real->message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) retval = FALSE; _dbus_type_writer_remove_types (&real->u.writer); _dbus_string_free (str); dbus_free (str); return retval; } /** * Frees the signature string and marks the iterator as not having a * type_str anymore. Since the new signature is not set, the message * will generally be hosed after this is called. * * @param real an iterator without a type_str */ static void _dbus_message_iter_abandon_signature (DBusMessageRealIter *real) { DBusString *str; _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); _dbus_assert (real->u.writer.type_str != NULL); _dbus_assert (real->sig_refcount > 0); real->sig_refcount -= 1; if (real->sig_refcount > 0) return; _dbus_assert (real->sig_refcount == 0); str = real->u.writer.type_str; _dbus_type_writer_remove_types (&real->u.writer); _dbus_string_free (str); dbus_free (str); } #ifndef DBUS_DISABLE_CHECKS static dbus_bool_t _dbus_message_iter_append_check (DBusMessageRealIter *iter) { if (!_dbus_message_iter_check (iter)) return FALSE; if (iter->message->locked) { _dbus_warn_check_failed ("dbus append iterator can't be used: message is locked (has already been sent)\n"); return FALSE; } return TRUE; } #endif /* DBUS_DISABLE_CHECKS */ #ifdef HAVE_UNIX_FD_PASSING static int * expand_fd_array(DBusMessage *m, unsigned n) { _dbus_assert(m); /* This makes space for adding n new fds to the array and returns a pointer to the place were the first fd should be put. */ if (m->n_unix_fds + n > m->n_unix_fds_allocated) { unsigned k; int *p; /* Make twice as much space as necessary */ k = (m->n_unix_fds + n) * 2; /* Allocate at least four */ if (k < 4) k = 4; p = dbus_realloc(m->unix_fds, k * sizeof(int)); if (p == NULL) return NULL; m->unix_fds = p; m->n_unix_fds_allocated = k; } return m->unix_fds + m->n_unix_fds; } #endif /** * Appends a basic-typed value to the message. The basic types are the * non-container types such as integer and string. * * The "value" argument should be the address of a basic-typed value. * So for string, const char**. For integer, dbus_int32_t*. * * For Unix file descriptors this function will internally duplicate * the descriptor you passed in. Hence you may close the descriptor * immediately after this call. * * @todo If this fails due to lack of memory, the message is hosed and * you have to start over building the whole message. * * @param iter the append iterator * @param type the type of the value * @param value the address of the value * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_iter_append_basic (DBusMessageIter *iter, int type, const void *value) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; dbus_bool_t ret; _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); _dbus_return_val_if_fail (dbus_type_is_basic (type), FALSE); _dbus_return_val_if_fail (value != NULL, FALSE); #ifndef DBUS_DISABLE_CHECKS switch (type) { const char * const *string_p; const dbus_bool_t *bool_p; case DBUS_TYPE_STRING: string_p = value; _dbus_return_val_if_fail (_dbus_check_is_valid_utf8 (*string_p), FALSE); break; case DBUS_TYPE_OBJECT_PATH: string_p = value; _dbus_return_val_if_fail (_dbus_check_is_valid_path (*string_p), FALSE); break; case DBUS_TYPE_SIGNATURE: string_p = value; _dbus_return_val_if_fail (_dbus_check_is_valid_signature (*string_p), FALSE); break; case DBUS_TYPE_BOOLEAN: bool_p = value; _dbus_return_val_if_fail (*bool_p == 0 || *bool_p == 1, FALSE); break; default: { /* nothing to check, all possible values are allowed */ } } #endif if (!_dbus_message_iter_open_signature (real)) return FALSE; if (type == DBUS_TYPE_UNIX_FD) { #ifdef HAVE_UNIX_FD_PASSING int *fds; dbus_uint32_t u; /* First step, include the fd in the fd list of this message */ if (!(fds = expand_fd_array(real->message, 1))) return FALSE; *fds = _dbus_dup(*(int*) value, NULL); if (*fds < 0) return FALSE; u = real->message->n_unix_fds; /* Second step, write the index to the fd */ if (!(ret = _dbus_type_writer_write_basic (&real->u.writer, DBUS_TYPE_UNIX_FD, &u))) { _dbus_close(*fds, NULL); return FALSE; } real->message->n_unix_fds += 1; u += 1; /* Final step, update the header accordingly */ ret = _dbus_header_set_field_basic (&real->message->header, DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32, &u); /* If any of these operations fail the message is hosed. However, no memory or fds should be leaked since what has been added to message has been added to the message, and can hence be accounted for when the message is being freed. */ #else ret = FALSE; #endif } else { ret = _dbus_type_writer_write_basic (&real->u.writer, type, value); } if (!_dbus_message_iter_close_signature (real)) ret = FALSE; return ret; } /** * Appends a block of fixed-length values to an array. The * fixed-length types are all basic types that are not string-like. So * int32, double, bool, etc. (Unix file descriptors however are not * supported.) You must call dbus_message_iter_open_container() to * open an array of values before calling this function. You may call * this function multiple times (and intermixed with calls to * dbus_message_iter_append_basic()) for the same array. * * The "value" argument should be the address of the array. So for * integer, "dbus_int32_t**" is expected for example. * * @warning in C, given "int array[]", "&array == array" (the * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). * So if you're using an array instead of a pointer you have to create * a pointer variable, assign the array to it, then take the address * of the pointer variable. * @code * const dbus_int32_t array[] = { 1, 2, 3 }; * const dbus_int32_t *v_ARRAY = array; * if (!dbus_message_iter_append_fixed_array (&iter, DBUS_TYPE_INT32, &v_ARRAY, 3)) * fprintf (stderr, "No memory!\n"); * @endcode * For strings it works to write const char *array = "Hello" and then * use &array though. * * @todo If this fails due to lack of memory, the message is hosed and * you have to start over building the whole message. * * @param iter the append iterator * @param element_type the type of the array elements * @param value the address of the array * @param n_elements the number of elements to append * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter *iter, int element_type, const void *value, int n_elements) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; dbus_bool_t ret; _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); _dbus_return_val_if_fail (dbus_type_is_fixed (element_type) && element_type != DBUS_TYPE_UNIX_FD, FALSE); _dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE); _dbus_return_val_if_fail (value != NULL, FALSE); _dbus_return_val_if_fail (n_elements >= 0, FALSE); _dbus_return_val_if_fail (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type), FALSE); #ifndef DBUS_DISABLE_CHECKS if (element_type == DBUS_TYPE_BOOLEAN) { const dbus_bool_t * const *bools = value; int i; for (i = 0; i < n_elements; i++) { _dbus_return_val_if_fail ((*bools)[i] == 0 || (*bools)[i] == 1, FALSE); } } #endif ret = _dbus_type_writer_write_fixed_multi (&real->u.writer, element_type, value, n_elements); return ret; } /** * Appends a container-typed value to the message; you are required to * append the contents of the container using the returned * sub-iterator, and then call * dbus_message_iter_close_container(). Container types are for * example struct, variant, and array. For variants, the * contained_signature should be the type of the single value inside * the variant. For structs and dict entries, contained_signature * should be #NULL; it will be set to whatever types you write into * the struct. For arrays, contained_signature should be the type of * the array elements. * * @todo If this fails due to lack of memory, the message is hosed and * you have to start over building the whole message. * * @param iter the append iterator * @param type the type of the value * @param contained_signature the type of container contents * @param sub sub-iterator to initialize * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_iter_open_container (DBusMessageIter *iter, int type, const char *contained_signature, DBusMessageIter *sub) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; DBusString contained_str; _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); _dbus_return_val_if_fail (dbus_type_is_container (type), FALSE); _dbus_return_val_if_fail (sub != NULL, FALSE); _dbus_return_val_if_fail ((type == DBUS_TYPE_STRUCT && contained_signature == NULL) || (type == DBUS_TYPE_DICT_ENTRY && contained_signature == NULL) || (type == DBUS_TYPE_VARIANT && contained_signature != NULL) || (type == DBUS_TYPE_ARRAY && contained_signature != NULL), FALSE); /* this would fail if the contained_signature is a dict entry, since * dict entries are invalid signatures standalone (they must be in * an array) */ _dbus_return_val_if_fail ((type == DBUS_TYPE_ARRAY && contained_signature && *contained_signature == DBUS_DICT_ENTRY_BEGIN_CHAR) || (contained_signature == NULL || _dbus_check_is_valid_signature (contained_signature)), FALSE); if (!_dbus_message_iter_open_signature (real)) return FALSE; *real_sub = *real; if (contained_signature != NULL) { _dbus_string_init_const (&contained_str, contained_signature); return _dbus_type_writer_recurse (&real->u.writer, type, &contained_str, 0, &real_sub->u.writer); } else { return _dbus_type_writer_recurse (&real->u.writer, type, NULL, 0, &real_sub->u.writer); } } /** * Closes a container-typed value appended to the message; may write * out more information to the message known only after the entire * container is written, and may free resources created by * dbus_message_iter_open_container(). * * @todo If this fails due to lack of memory, the message is hosed and * you have to start over building the whole message. * * @param iter the append iterator * @param sub sub-iterator to close * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_iter_close_container (DBusMessageIter *iter, DBusMessageIter *sub) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; dbus_bool_t ret; _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); _dbus_return_val_if_fail (_dbus_message_iter_append_check (real_sub), FALSE); _dbus_return_val_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); ret = _dbus_type_writer_unrecurse (&real->u.writer, &real_sub->u.writer); if (!_dbus_message_iter_close_signature (real)) ret = FALSE; return ret; } /** * Abandons creation of a contained-typed value and frees resources created * by dbus_message_iter_open_container(). Once this returns, the message * is hosed and you have to start over building the whole message. * * This should only be used to abandon creation of a message when you have * open containers. * * @param iter the append iterator * @param sub sub-iterator to close */ void dbus_message_iter_abandon_container (DBusMessageIter *iter, DBusMessageIter *sub) { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; #ifndef DBUS_DISABLE_CHECKS DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; _dbus_return_if_fail (_dbus_message_iter_append_check (real)); _dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); _dbus_return_if_fail (_dbus_message_iter_append_check (real_sub)); _dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); #endif _dbus_message_iter_abandon_signature (real); } /** * Sets a flag indicating that the message does not want a reply; if * this flag is set, the other end of the connection may (but is not * required to) optimize by not sending method return or error * replies. If this flag is set, there is no way to know whether the * message successfully arrived at the remote end. Normally you know a * message was received when you receive the reply to it. * * The flag is #FALSE by default, that is by default the other end is * required to reply. * * On the protocol level this toggles #DBUS_HEADER_FLAG_NO_REPLY_EXPECTED * * @param message the message * @param no_reply #TRUE if no reply is desired */ void dbus_message_set_no_reply (DBusMessage *message, dbus_bool_t no_reply) { _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); _dbus_header_toggle_flag (&message->header, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, no_reply); } /** * Returns #TRUE if the message does not expect * a reply. * * @param message the message * @returns #TRUE if the message sender isn't waiting for a reply */ dbus_bool_t dbus_message_get_no_reply (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, FALSE); return _dbus_header_get_flag (&message->header, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED); } /** * Sets a flag indicating that an owner for the destination name will * be automatically started before the message is delivered. When this * flag is set, the message is held until a name owner finishes * starting up, or fails to start up. In case of failure, the reply * will be an error. * * The flag is set to #TRUE by default, i.e. auto starting is the default. * * On the protocol level this toggles #DBUS_HEADER_FLAG_NO_AUTO_START * * @param message the message * @param auto_start #TRUE if auto-starting is desired */ void dbus_message_set_auto_start (DBusMessage *message, dbus_bool_t auto_start) { _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); _dbus_header_toggle_flag (&message->header, DBUS_HEADER_FLAG_NO_AUTO_START, !auto_start); } /** * Returns #TRUE if the message will cause an owner for * destination name to be auto-started. * * @param message the message * @returns #TRUE if the message will use auto-start */ dbus_bool_t dbus_message_get_auto_start (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, FALSE); return !_dbus_header_get_flag (&message->header, DBUS_HEADER_FLAG_NO_AUTO_START); } /** * Sets the object path this message is being sent to (for * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL). * * The path must contain only valid characters as defined * in the D-Bus specification. * * @param message the message * @param object_path the path or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_path (DBusMessage *message, const char *object_path) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (object_path == NULL || _dbus_check_is_valid_path (object_path), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH, object_path); } /** * Gets the object path this message is being sent to (for * DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted from (for * DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none. * * See also dbus_message_get_path_decomposed(). * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the path (should not be freed) or #NULL */ const char* dbus_message_get_path (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH, (void *) &v); return v; } /** * Checks if the message has a particular object path. The object * path is the destination object for a method call or the emitting * object for a signal. * * @param message the message * @param path the path name * @returns #TRUE if there is a path field in the header */ dbus_bool_t dbus_message_has_path (DBusMessage *message, const char *path) { const char *msg_path; msg_path = dbus_message_get_path (message); if (msg_path == NULL) { if (path == NULL) return TRUE; else return FALSE; } if (path == NULL) return FALSE; if (strcmp (msg_path, path) == 0) return TRUE; return FALSE; } /** * Gets the object path this message is being sent to * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed * format (one array element per path component). * Free the returned array with dbus_free_string_array(). * * An empty but non-NULL path array means the path "/". * So the path "/foo/bar" becomes { "foo", "bar", NULL } * and the path "/" becomes { NULL }. * * See also dbus_message_get_path(). * * @todo this could be optimized by using the len from the message * instead of calling strlen() again * * @param message the message * @param path place to store allocated array of path components; #NULL set here if no path field exists * @returns #FALSE if no memory to allocate the array */ dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message, char ***path) { const char *v; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); *path = NULL; v = dbus_message_get_path (message); if (v != NULL) { if (!_dbus_decompose_path (v, strlen (v), path, NULL)) return FALSE; } return TRUE; } /** * Sets the interface this message is being sent to * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or * the interface a signal is being emitted from * (for DBUS_MESSAGE_TYPE_SIGNAL). * * The interface name must contain only valid characters as defined * in the D-Bus specification. * * @param message the message * @param iface the interface or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_interface (DBusMessage *message, const char *iface) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (iface == NULL || _dbus_check_is_valid_interface (iface), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING, iface); } /** * Gets the interface this message is being sent to * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted * from (for DBUS_MESSAGE_TYPE_SIGNAL). * The interface name is fully-qualified (namespaced). * Returns #NULL if none. * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the message interface (should not be freed) or #NULL */ const char* dbus_message_get_interface (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING, (void *) &v); return v; } /** * Checks if the message has an interface * * @param message the message * @param iface the interface name * @returns #TRUE if the interface field in the header matches */ dbus_bool_t dbus_message_has_interface (DBusMessage *message, const char *iface) { const char *msg_interface; msg_interface = dbus_message_get_interface (message); if (msg_interface == NULL) { if (iface == NULL) return TRUE; else return FALSE; } if (iface == NULL) return FALSE; if (strcmp (msg_interface, iface) == 0) return TRUE; return FALSE; } /** * Sets the interface member being invoked * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted * (DBUS_MESSAGE_TYPE_SIGNAL). * * The member name must contain only valid characters as defined * in the D-Bus specification. * * @param message the message * @param member the member or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_member (DBusMessage *message, const char *member) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (member == NULL || _dbus_check_is_valid_member (member), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING, member); } /** * Gets the interface member being invoked * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted * (DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none. * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the member name (should not be freed) or #NULL */ const char* dbus_message_get_member (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING, (void *) &v); return v; } /** * Checks if the message has an interface member * * @param message the message * @param member the member name * @returns #TRUE if there is a member field in the header */ dbus_bool_t dbus_message_has_member (DBusMessage *message, const char *member) { const char *msg_member; msg_member = dbus_message_get_member (message); if (msg_member == NULL) { if (member == NULL) return TRUE; else return FALSE; } if (member == NULL) return FALSE; if (strcmp (msg_member, member) == 0) return TRUE; return FALSE; } /** * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR). * The name is fully-qualified (namespaced). * * The error name must contain only valid characters as defined * in the D-Bus specification. * * @param message the message * @param error_name the name or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_error_name (DBusMessage *message, const char *error_name) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (error_name == NULL || _dbus_check_is_valid_error_name (error_name), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING, error_name); } /** * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only) * or #NULL if none. * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the error name (should not be freed) or #NULL */ const char* dbus_message_get_error_name (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING, (void *) &v); return v; } /** * Sets the message's destination. The destination is the name of * another connection on the bus and may be either the unique name * assigned by the bus to each connection, or a well-known name * specified in advance. * * The destination name must contain only valid characters as defined * in the D-Bus specification. * * @param message the message * @param destination the destination name or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_destination (DBusMessage *message, const char *destination) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (destination == NULL || _dbus_check_is_valid_bus_name (destination), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING, destination); } /** * Gets the destination of a message or #NULL if there is none set. * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the message destination (should not be freed) or #NULL */ const char* dbus_message_get_destination (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING, (void *) &v); return v; } /** * Sets the message sender. * * The sender must be a valid bus name as defined in the D-Bus * specification. * * Usually you don't want to call this. The message bus daemon will * call it to set the origin of each message. If you aren't implementing * a message bus daemon you shouldn't need to set the sender. * * @param message the message * @param sender the sender or #NULL to unset * @returns #FALSE if not enough memory */ dbus_bool_t dbus_message_set_sender (DBusMessage *message, const char *sender) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); _dbus_return_val_if_fail (sender == NULL || _dbus_check_is_valid_bus_name (sender), FALSE); return set_or_delete_string_field (message, DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING, sender); } /** * Gets the unique name of the connection which originated this * message, or #NULL if unknown or inapplicable. The sender is filled * in by the message bus. * * Note, the returned sender is always the unique bus name. * Connections may own multiple other bus names, but those * are not found in the sender field. * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the unique name of the sender or #NULL */ const char* dbus_message_get_sender (DBusMessage *message) { const char *v; _dbus_return_val_if_fail (message != NULL, NULL); v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING, (void *) &v); return v; } /** * Gets the type signature of the message, i.e. the arguments in the * message payload. The signature includes only "in" arguments for * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from * what you might expect (that is, it does not include the signature of the * entire C++-style method). * * The signature is a string made up of type codes such as * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also * the value of #DBUS_TYPE_INVALID). * * The returned string becomes invalid if the message is * modified, since it points into the wire-marshaled message data. * * @param message the message * @returns the type signature */ const char* dbus_message_get_signature (DBusMessage *message) { const DBusString *type_str; int type_pos; _dbus_return_val_if_fail (message != NULL, NULL); get_const_signature (&message->header, &type_str, &type_pos); return _dbus_string_get_const_data_len (type_str, type_pos, 0); } static dbus_bool_t _dbus_message_has_type_interface_member (DBusMessage *message, int type, const char *iface, const char *member) { const char *n; _dbus_assert (message != NULL); _dbus_assert (iface != NULL); _dbus_assert (member != NULL); if (dbus_message_get_type (message) != type) return FALSE; /* Optimize by checking the short member name first * instead of the longer interface name */ n = dbus_message_get_member (message); if (n && strcmp (n, member) == 0) { n = dbus_message_get_interface (message); if (n == NULL || strcmp (n, iface) == 0) return TRUE; } return FALSE; } /** * Checks whether the message is a method call with the given * interface and member fields. If the message is not * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or * member field, returns #FALSE. If the interface field is missing, * then it will be assumed equal to the provided interface. The D-Bus * protocol allows method callers to leave out the interface name. * * @param message the message * @param iface the name to check (must not be #NULL) * @param method the name to check (must not be #NULL) * * @returns #TRUE if the message is the specified method call */ dbus_bool_t dbus_message_is_method_call (DBusMessage *message, const char *iface, const char *method) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (iface != NULL, FALSE); _dbus_return_val_if_fail (method != NULL, FALSE); /* don't check that interface/method are valid since it would be * expensive, and not catch many common errors */ return _dbus_message_has_type_interface_member (message, DBUS_MESSAGE_TYPE_METHOD_CALL, iface, method); } /** * Checks whether the message is a signal with the given interface and * member fields. If the message is not #DBUS_MESSAGE_TYPE_SIGNAL, or * has a different interface or member field, returns #FALSE. * * @param message the message * @param iface the name to check (must not be #NULL) * @param signal_name the name to check (must not be #NULL) * * @returns #TRUE if the message is the specified signal */ dbus_bool_t dbus_message_is_signal (DBusMessage *message, const char *iface, const char *signal_name) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (iface != NULL, FALSE); _dbus_return_val_if_fail (signal_name != NULL, FALSE); /* don't check that interface/name are valid since it would be * expensive, and not catch many common errors */ return _dbus_message_has_type_interface_member (message, DBUS_MESSAGE_TYPE_SIGNAL, iface, signal_name); } /** * Checks whether the message is an error reply with the given error * name. If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a * different name, returns #FALSE. * * @param message the message * @param error_name the name to check (must not be #NULL) * * @returns #TRUE if the message is the specified error */ dbus_bool_t dbus_message_is_error (DBusMessage *message, const char *error_name) { const char *n; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (error_name != NULL, FALSE); /* don't check that error_name is valid since it would be expensive, * and not catch many common errors */ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) return FALSE; n = dbus_message_get_error_name (message); if (n && strcmp (n, error_name) == 0) return TRUE; else return FALSE; } /** * Checks whether the message was sent to the given name. If the * message has no destination specified or has a different * destination, returns #FALSE. * * @param message the message * @param name the name to check (must not be #NULL) * * @returns #TRUE if the message has the given destination name */ dbus_bool_t dbus_message_has_destination (DBusMessage *message, const char *name) { const char *s; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (name != NULL, FALSE); /* don't check that name is valid since it would be expensive, and * not catch many common errors */ s = dbus_message_get_destination (message); if (s && strcmp (s, name) == 0) return TRUE; else return FALSE; } /** * Checks whether the message has the given unique name as its sender. * If the message has no sender specified or has a different sender, * returns #FALSE. Note that a peer application will always have the * unique name of the connection as the sender. So you can't use this * function to see whether a sender owned a well-known name. * * Messages from the bus itself will have #DBUS_SERVICE_DBUS * as the sender. * * @param message the message * @param name the name to check (must not be #NULL) * * @returns #TRUE if the message has the given sender */ dbus_bool_t dbus_message_has_sender (DBusMessage *message, const char *name) { const char *s; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (name != NULL, FALSE); /* don't check that name is valid since it would be expensive, and * not catch many common errors */ s = dbus_message_get_sender (message); if (s && strcmp (s, name) == 0) return TRUE; else return FALSE; } /** * Checks whether the message has the given signature; see * dbus_message_get_signature() for more details on what the signature * looks like. * * @param message the message * @param signature typecode array * @returns #TRUE if message has the given signature */ dbus_bool_t dbus_message_has_signature (DBusMessage *message, const char *signature) { const char *s; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (signature != NULL, FALSE); /* don't check that signature is valid since it would be expensive, * and not catch many common errors */ s = dbus_message_get_signature (message); if (s && strcmp (s, signature) == 0) return TRUE; else return FALSE; } /** * Sets a #DBusError based on the contents of the given * message. The error is only set if the message * is an error message, as in #DBUS_MESSAGE_TYPE_ERROR. * The name of the error is set to the name of the message, * and the error message is set to the first argument * if the argument exists and is a string. * * The return value indicates whether the error was set (the error is * set if and only if the message is an error message). So you can * check for an error reply and convert it to DBusError in one go: * @code * if (dbus_set_error_from_message (error, reply)) * return error; * else * process reply; * @endcode * * @param error the error to set * @param message the message to set it from * @returns #TRUE if the message had type #DBUS_MESSAGE_TYPE_ERROR */ dbus_bool_t dbus_set_error_from_message (DBusError *error, DBusMessage *message) { const char *str; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) return FALSE; str = NULL; dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); dbus_set_error (error, dbus_message_get_error_name (message), str ? "%s" : NULL, str); return TRUE; } /** * Checks whether a message contains unix fds * * @param message the message * @returns #TRUE if the message contains unix fds */ dbus_bool_t dbus_message_contains_unix_fds(DBusMessage *message) { #ifdef HAVE_UNIX_FD_PASSING _dbus_assert(message); return message->n_unix_fds > 0; #else return FALSE; #endif } /** @} */ /** * @addtogroup DBusMessageInternals * * @{ */ /** * The initial buffer size of the message loader. * * @todo this should be based on min header size plus some average * body size, or something. Or rather, the min header size only, if we * want to try to read only the header, store that in a DBusMessage, * then read only the body and store that, etc., depends on * how we optimize _dbus_message_loader_get_buffer() and what * the exact message format is. */ #define INITIAL_LOADER_DATA_LEN 32 /** * Creates a new message loader. Returns #NULL if memory can't * be allocated. * * @returns new loader, or #NULL. */ DBusMessageLoader* _dbus_message_loader_new (void) { DBusMessageLoader *loader; loader = dbus_new0 (DBusMessageLoader, 1); if (loader == NULL) return NULL; loader->refcount = 1; loader->corrupted = FALSE; loader->corruption_reason = DBUS_VALID; /* this can be configured by the app, but defaults to the protocol max */ loader->max_message_size = DBUS_MAXIMUM_MESSAGE_LENGTH; /* We set a very relatively conservative default here since due to how SCM_RIGHTS works we need to preallocate an fd array of the maximum number of unix fds we want to receive in advance. A try-and-reallocate loop is not possible. */ loader->max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS; if (!_dbus_string_init (&loader->data)) { dbus_free (loader); return NULL; } /* preallocate the buffer for speed, ignore failure */ _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN); _dbus_string_set_length (&loader->data, 0); #ifdef HAVE_UNIX_FD_PASSING loader->unix_fds = NULL; loader->n_unix_fds = loader->n_unix_fds_allocated = 0; loader->unix_fds_outstanding = FALSE; #endif return loader; } /** * Increments the reference count of the loader. * * @param loader the loader. * @returns the loader */ DBusMessageLoader * _dbus_message_loader_ref (DBusMessageLoader *loader) { loader->refcount += 1; return loader; } /** * Decrements the reference count of the loader and finalizes the * loader when the count reaches zero. * * @param loader the loader. */ void _dbus_message_loader_unref (DBusMessageLoader *loader) { loader->refcount -= 1; if (loader->refcount == 0) { #ifdef HAVE_UNIX_FD_PASSING close_unix_fds(loader->unix_fds, &loader->n_unix_fds); dbus_free(loader->unix_fds); #endif _dbus_list_foreach (&loader->messages, (DBusForeachFunction) dbus_message_unref, NULL); _dbus_list_clear (&loader->messages); _dbus_string_free (&loader->data); dbus_free (loader); } } /** * Gets the buffer to use for reading data from the network. Network * data is read directly into an allocated buffer, which is then used * in the DBusMessage, to avoid as many extra memcpy's as possible. * The buffer must always be returned immediately using * _dbus_message_loader_return_buffer(), even if no bytes are * successfully read. * * @todo this function can be a lot more clever. For example * it can probably always return a buffer size to read exactly * the body of the next message, thus avoiding any memory wastage * or reallocs. * * @todo we need to enforce a max length on strings in header fields. * * @param loader the message loader. * @param buffer the buffer */ void _dbus_message_loader_get_buffer (DBusMessageLoader *loader, DBusString **buffer) { _dbus_assert (!loader->buffer_outstanding); *buffer = &loader->data; loader->buffer_outstanding = TRUE; } /** * Returns a buffer obtained from _dbus_message_loader_get_buffer(), * indicating to the loader how many bytes of the buffer were filled * in. This function must always be called, even if no bytes were * successfully read. * * @param loader the loader. * @param buffer the buffer. */ void _dbus_message_loader_return_buffer (DBusMessageLoader *loader, DBusString *buffer) { _dbus_assert (loader->buffer_outstanding); _dbus_assert (buffer == &loader->data); loader->buffer_outstanding = FALSE; } /** * Gets the buffer to use for reading unix fds from the network. * * This works similar to _dbus_message_loader_get_buffer() * * @param loader the message loader. * @param fds the array to read fds into * @param max_n_fds how many fds to read at most * @return TRUE on success, FALSE on OOM */ dbus_bool_t _dbus_message_loader_get_unix_fds(DBusMessageLoader *loader, int **fds, unsigned *max_n_fds) { #ifdef HAVE_UNIX_FD_PASSING _dbus_assert (!loader->unix_fds_outstanding); /* Allocate space where we can put the fds we read. We allocate space for max_message_unix_fds since this is an upper limit how many fds can be received within a single message. Since SCM_RIGHTS doesn't allow a reallocate+retry logic we are allocating the maximum possible array size right from the beginning. This sucks a bit, however unless SCM_RIGHTS is fixed there is no better way. */ if (loader->n_unix_fds_allocated < loader->max_message_unix_fds) { int *a = dbus_realloc(loader->unix_fds, loader->max_message_unix_fds * sizeof(loader->unix_fds[0])); if (!a) return FALSE; loader->unix_fds = a; loader->n_unix_fds_allocated = loader->max_message_unix_fds; } *fds = loader->unix_fds + loader->n_unix_fds; *max_n_fds = loader->n_unix_fds_allocated - loader->n_unix_fds; loader->unix_fds_outstanding = TRUE; return TRUE; #else _dbus_assert_not_reached("Platform doesn't support unix fd passing"); return FALSE; #endif } /** * Returns a buffer obtained from _dbus_message_loader_get_unix_fds(). * * This works similar to _dbus_message_loader_return_buffer() * * @param loader the message loader. * @param fds the array fds were read into * @param n_fds how many fds were read */ void _dbus_message_loader_return_unix_fds(DBusMessageLoader *loader, int *fds, unsigned n_fds) { #ifdef HAVE_UNIX_FD_PASSING _dbus_assert(loader->unix_fds_outstanding); _dbus_assert(loader->unix_fds + loader->n_unix_fds == fds); _dbus_assert(loader->n_unix_fds + n_fds <= loader->n_unix_fds_allocated); loader->n_unix_fds += n_fds; loader->unix_fds_outstanding = FALSE; if (n_fds && loader->unix_fds_change) loader->unix_fds_change (loader->unix_fds_change_data); #else _dbus_assert_not_reached("Platform doesn't support unix fd passing"); #endif } /* * FIXME when we move the header out of the buffer, that memmoves all * buffered messages. Kind of crappy. * * Also we copy the header and body, which is kind of crappy. To * avoid this, we have to allow header and body to be in a single * memory block, which is good for messages we read and bad for * messages we are creating. But we could move_len() the buffer into * this single memory block, and move_len() will just swap the buffers * if you're moving the entire buffer replacing the dest string. * * We could also have the message loader tell the transport how many * bytes to read; so it would first ask for some arbitrary number like * 256, then if the message was incomplete it would use the * header/body len to ask for exactly the size of the message (or * blocks the size of a typical kernel buffer for the socket). That * way we don't get trailing bytes in the buffer that have to be * memmoved. Though I suppose we also don't have a chance of reading a * bunch of small messages at once, so the optimization may be stupid. * * Another approach would be to keep a "start" index into * loader->data and only delete it occasionally, instead of after * each message is loaded. * * load_message() returns FALSE if not enough memory OR the loader was corrupted */ static dbus_bool_t load_message (DBusMessageLoader *loader, DBusMessage *message, int byte_order, int fields_array_len, int header_len, int body_len) { dbus_bool_t oom; DBusValidity validity; const DBusString *type_str; int type_pos; DBusValidationMode mode; dbus_uint32_t n_unix_fds = 0; mode = DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED; oom = FALSE; #if 0 _dbus_verbose_bytes_of_string (&loader->data, 0, header_len /* + body_len */); #endif /* 1. VALIDATE AND COPY OVER HEADER */ _dbus_assert (_dbus_string_get_length (&message->header.data) == 0); _dbus_assert ((header_len + body_len) <= _dbus_string_get_length (&loader->data)); if (!_dbus_header_load (&message->header, mode, &validity, byte_order, fields_array_len, header_len, body_len, &loader->data, 0, _dbus_string_get_length (&loader->data))) { _dbus_verbose ("Failed to load header for new message code %d\n", validity); /* assert here so we can catch any code that still uses DBUS_VALID to indicate oom errors. They should use DBUS_VALIDITY_UNKNOWN_OOM_ERROR instead */ _dbus_assert (validity != DBUS_VALID); if (validity == DBUS_VALIDITY_UNKNOWN_OOM_ERROR) oom = TRUE; else { loader->corrupted = TRUE; loader->corruption_reason = validity; } goto failed; } _dbus_assert (validity == DBUS_VALID); /* 2. VALIDATE BODY */ if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { get_const_signature (&message->header, &type_str, &type_pos); /* Because the bytes_remaining arg is NULL, this validates that the * body is the right length */ validity = _dbus_validate_body_with_reason (type_str, type_pos, byte_order, NULL, &loader->data, header_len, body_len); if (validity != DBUS_VALID) { _dbus_verbose ("Failed to validate message body code %d\n", validity); loader->corrupted = TRUE; loader->corruption_reason = validity; goto failed; } } /* 3. COPY OVER UNIX FDS */ _dbus_header_get_field_basic(&message->header, DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32, &n_unix_fds); #ifdef HAVE_UNIX_FD_PASSING if (n_unix_fds > loader->n_unix_fds) { _dbus_verbose("Message contains references to more unix fds than were sent %u != %u\n", n_unix_fds, loader->n_unix_fds); loader->corrupted = TRUE; loader->corruption_reason = DBUS_INVALID_MISSING_UNIX_FDS; goto failed; } /* If this was a recycled message there might still be some memory allocated for the fds */ dbus_free(message->unix_fds); if (n_unix_fds > 0) { message->unix_fds = _dbus_memdup(loader->unix_fds, n_unix_fds * sizeof(message->unix_fds[0])); if (message->unix_fds == NULL) { _dbus_verbose ("Failed to allocate file descriptor array\n"); oom = TRUE; goto failed; } message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds; loader->n_unix_fds -= n_unix_fds; memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0])); if (loader->unix_fds_change) loader->unix_fds_change (loader->unix_fds_change_data); } else message->unix_fds = NULL; #else if (n_unix_fds > 0) { _dbus_verbose ("Hmm, message claims to come with file descriptors " "but that's not supported on our platform, disconnecting.\n"); loader->corrupted = TRUE; loader->corruption_reason = DBUS_INVALID_MISSING_UNIX_FDS; goto failed; } #endif /* 3. COPY OVER BODY AND QUEUE MESSAGE */ if (!_dbus_list_append (&loader->messages, message)) { _dbus_verbose ("Failed to append new message to loader queue\n"); oom = TRUE; goto failed; } _dbus_assert (_dbus_string_get_length (&message->body) == 0); _dbus_assert (_dbus_string_get_length (&loader->data) >= (header_len + body_len)); if (!_dbus_string_copy_len (&loader->data, header_len, body_len, &message->body, 0)) { _dbus_verbose ("Failed to move body into new message\n"); oom = TRUE; goto failed; } _dbus_string_delete (&loader->data, 0, header_len + body_len); /* don't waste more than 2k of memory */ _dbus_string_compact (&loader->data, 2048); _dbus_assert (_dbus_string_get_length (&message->header.data) == header_len); _dbus_assert (_dbus_string_get_length (&message->body) == body_len); _dbus_verbose ("Loaded message %p\n", message); _dbus_assert (!oom); _dbus_assert (!loader->corrupted); _dbus_assert (loader->messages != NULL); _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL); return TRUE; failed: /* Clean up */ /* does nothing if the message isn't in the list */ _dbus_list_remove_last (&loader->messages, message); if (oom) _dbus_assert (!loader->corrupted); else _dbus_assert (loader->corrupted); _dbus_verbose_bytes_of_string (&loader->data, 0, _dbus_string_get_length (&loader->data)); return FALSE; } /** * Converts buffered data into messages, if we have enough data. If * we don't have enough data, does nothing. * * @todo we need to check that the proper named header fields exist * for each message type. * * @todo If a message has unknown type, we should probably eat it * right here rather than passing it out to applications. However * it's not an error to see messages of unknown type. * * @param loader the loader. * @returns #TRUE if we had enough memory to finish. */ dbus_bool_t _dbus_message_loader_queue_messages (DBusMessageLoader *loader) { while (!loader->corrupted && _dbus_string_get_length (&loader->data) >= DBUS_MINIMUM_HEADER_SIZE) { DBusValidity validity; int byte_order, fields_array_len, header_len, body_len; if (_dbus_header_have_message_untrusted (loader->max_message_size, &validity, &byte_order, &fields_array_len, &header_len, &body_len, &loader->data, 0, _dbus_string_get_length (&loader->data))) { DBusMessage *message; _dbus_assert (validity == DBUS_VALID); message = dbus_message_new_empty_header (); if (message == NULL) return FALSE; if (!load_message (loader, message, byte_order, fields_array_len, header_len, body_len)) { dbus_message_unref (message); /* load_message() returns false if corrupted or OOM; if * corrupted then return TRUE for not OOM */ return loader->corrupted; } _dbus_assert (loader->messages != NULL); _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL); } else { _dbus_verbose ("Initial peek at header says we don't have a whole message yet, or data broken with invalid code %d\n", validity); if (validity != DBUS_VALID) { loader->corrupted = TRUE; loader->corruption_reason = validity; } return TRUE; } } return TRUE; } /** * Peeks at first loaded message, returns #NULL if no messages have * been queued. * * @param loader the loader. * @returns the next message, or #NULL if none. */ DBusMessage* _dbus_message_loader_peek_message (DBusMessageLoader *loader) { if (loader->messages) return loader->messages->data; else return NULL; } /** * Pops a loaded message (passing ownership of the message * to the caller). Returns #NULL if no messages have been * queued. * * @param loader the loader. * @returns the next message, or #NULL if none. */ DBusMessage* _dbus_message_loader_pop_message (DBusMessageLoader *loader) { return _dbus_list_pop_first (&loader->messages); } /** * Pops a loaded message inside a list link (passing ownership of the * message and link to the caller). Returns #NULL if no messages have * been loaded. * * @param loader the loader. * @returns the next message link, or #NULL if none. */ DBusList* _dbus_message_loader_pop_message_link (DBusMessageLoader *loader) { return _dbus_list_pop_first_link (&loader->messages); } /** * Returns a popped message link, used to undo a pop. * * @param loader the loader * @param link the link with a message in it */ void _dbus_message_loader_putback_message_link (DBusMessageLoader *loader, DBusList *link) { _dbus_list_prepend_link (&loader->messages, link); } /** * Checks whether the loader is confused due to bad data. * If messages are received that are invalid, the * loader gets confused and gives up permanently. * This state is called "corrupted." * * @param loader the loader * @returns #TRUE if the loader is hosed. */ dbus_bool_t _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader) { _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) || (!loader->corrupted && loader->corruption_reason == DBUS_VALID)); return loader->corrupted; } /** * Checks what kind of bad data confused the loader. * * @param loader the loader * @returns why the loader is hosed, or DBUS_VALID if it isn't. */ DBusValidity _dbus_message_loader_get_corruption_reason (DBusMessageLoader *loader) { _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) || (!loader->corrupted && loader->corruption_reason == DBUS_VALID)); return loader->corruption_reason; } /** * Sets the maximum size message we allow. * * @param loader the loader * @param size the max message size in bytes */ void _dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, long size) { if (size > DBUS_MAXIMUM_MESSAGE_LENGTH) { _dbus_verbose ("clamping requested max message size %ld to %d\n", size, DBUS_MAXIMUM_MESSAGE_LENGTH); size = DBUS_MAXIMUM_MESSAGE_LENGTH; } loader->max_message_size = size; } /** * Gets the maximum allowed message size in bytes. * * @param loader the loader * @returns max size in bytes */ long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader) { return loader->max_message_size; } /** * Sets the maximum unix fds per message we allow. * * @param loader the loader * @param n the max number of unix fds in a message */ void _dbus_message_loader_set_max_message_unix_fds (DBusMessageLoader *loader, long n) { if (n > DBUS_MAXIMUM_MESSAGE_UNIX_FDS) { _dbus_verbose ("clamping requested max message unix_fds %ld to %d\n", n, DBUS_MAXIMUM_MESSAGE_UNIX_FDS); n = DBUS_MAXIMUM_MESSAGE_UNIX_FDS; } loader->max_message_unix_fds = n; } /** * Gets the maximum allowed number of unix fds per message * * @param loader the loader * @returns max unix fds */ long _dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader *loader) { return loader->max_message_unix_fds; } /** * Return how many file descriptors are pending in the loader * * @param loader the loader */ int _dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader) { #ifdef HAVE_UNIX_FD_PASSING return loader->n_unix_fds; #else return 0; #endif } /** * Register a function to be called whenever the number of pending file * descriptors in the loader change. * * @param loader the loader * @param callback the callback * @param data the data for the callback */ void _dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, void (* callback) (void *), void *data) { #ifdef HAVE_UNIX_FD_PASSING loader->unix_fds_change = callback; loader->unix_fds_change_data = data; #endif } static DBusDataSlotAllocator slot_allocator = _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots)); /** * Allocates an integer ID to be used for storing application-specific * data on any DBusMessage. The allocated ID may then be used * with dbus_message_set_data() and dbus_message_get_data(). * The passed-in slot must be initialized to -1, and is filled in * with the slot ID. If the passed-in slot is not -1, it's assumed * to be already allocated, and its refcount is incremented. * * The allocated slot is global, i.e. all DBusMessage objects will * have a slot with the given integer ID reserved. * * @param slot_p address of a global variable storing the slot * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t *slot_p) { return _dbus_data_slot_allocator_alloc (&slot_allocator, slot_p); } /** * Deallocates a global ID for message data slots. * dbus_message_get_data() and dbus_message_set_data() may no * longer be used with this slot. Existing data stored on existing * DBusMessage objects will be freed when the message is * finalized, but may not be retrieved (and may only be replaced if * someone else reallocates the slot). When the refcount on the * passed-in slot reaches 0, it is set to -1. * * @param slot_p address storing the slot to deallocate */ void dbus_message_free_data_slot (dbus_int32_t *slot_p) { _dbus_return_if_fail (*slot_p >= 0); _dbus_data_slot_allocator_free (&slot_allocator, slot_p); } /** * Stores a pointer on a DBusMessage, along * with an optional function to be used for freeing * the data when the data is set again, or when * the message is finalized. The slot number * must have been allocated with dbus_message_allocate_data_slot(). * * @param message the message * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t dbus_message_set_data (DBusMessage *message, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func) { DBusFreeFunction old_free_func; void *old_data; dbus_bool_t retval; _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (slot >= 0, FALSE); retval = _dbus_data_slot_list_set (&slot_allocator, &message->slot_list, slot, data, free_data_func, &old_free_func, &old_data); if (retval) { /* Do the actual free outside the message lock */ if (old_free_func) (* old_free_func) (old_data); } return retval; } /** * Retrieves data previously set with dbus_message_set_data(). * The slot must still be allocated (must not have been freed). * * @param message the message * @param slot the slot to get data from * @returns the data, or #NULL if not found */ void* dbus_message_get_data (DBusMessage *message, dbus_int32_t slot) { void *res; _dbus_return_val_if_fail (message != NULL, NULL); res = _dbus_data_slot_list_get (&slot_allocator, &message->slot_list, slot); return res; } /** * Utility function to convert a machine-readable (not translated) * string into a D-Bus message type. * * @code * "method_call" -> DBUS_MESSAGE_TYPE_METHOD_CALL * "method_return" -> DBUS_MESSAGE_TYPE_METHOD_RETURN * "signal" -> DBUS_MESSAGE_TYPE_SIGNAL * "error" -> DBUS_MESSAGE_TYPE_ERROR * anything else -> DBUS_MESSAGE_TYPE_INVALID * @endcode * */ int dbus_message_type_from_string (const char *type_str) { if (strcmp (type_str, "method_call") == 0) return DBUS_MESSAGE_TYPE_METHOD_CALL; if (strcmp (type_str, "method_return") == 0) return DBUS_MESSAGE_TYPE_METHOD_RETURN; else if (strcmp (type_str, "signal") == 0) return DBUS_MESSAGE_TYPE_SIGNAL; else if (strcmp (type_str, "error") == 0) return DBUS_MESSAGE_TYPE_ERROR; else return DBUS_MESSAGE_TYPE_INVALID; } /** * Utility function to convert a D-Bus message type into a * machine-readable string (not translated). * * @code * DBUS_MESSAGE_TYPE_METHOD_CALL -> "method_call" * DBUS_MESSAGE_TYPE_METHOD_RETURN -> "method_return" * DBUS_MESSAGE_TYPE_SIGNAL -> "signal" * DBUS_MESSAGE_TYPE_ERROR -> "error" * DBUS_MESSAGE_TYPE_INVALID -> "invalid" * @endcode * */ const char * dbus_message_type_to_string (int type) { switch (type) { case DBUS_MESSAGE_TYPE_METHOD_CALL: return "method_call"; case DBUS_MESSAGE_TYPE_METHOD_RETURN: return "method_return"; case DBUS_MESSAGE_TYPE_SIGNAL: return "signal"; case DBUS_MESSAGE_TYPE_ERROR: return "error"; default: return "invalid"; } } /** * Turn a DBusMessage into the marshalled form as described in the D-Bus * specification. * * Generally, this function is only useful for encapsulating D-Bus messages in * a different protocol. * * @param msg the DBusMessage * @param marshalled_data_p the location to save the marshalled form to * @param len_p the location to save the length of the marshalled form to * @returns #FALSE if there was not enough memory */ dbus_bool_t dbus_message_marshal (DBusMessage *msg, char **marshalled_data_p, int *len_p) { DBusString tmp; dbus_bool_t was_locked; _dbus_return_val_if_fail (msg != NULL, FALSE); _dbus_return_val_if_fail (marshalled_data_p != NULL, FALSE); _dbus_return_val_if_fail (len_p != NULL, FALSE); if (!_dbus_string_init (&tmp)) return FALSE; /* Ensure the message is locked, to ensure the length header is filled in. */ was_locked = msg->locked; if (!was_locked) dbus_message_lock (msg); if (!_dbus_string_copy (&(msg->header.data), 0, &tmp, 0)) goto fail; *len_p = _dbus_string_get_length (&tmp); if (!_dbus_string_copy (&(msg->body), 0, &tmp, *len_p)) goto fail; *len_p = _dbus_string_get_length (&tmp); if (!_dbus_string_steal_data (&tmp, marshalled_data_p)) goto fail; _dbus_string_free (&tmp); if (!was_locked) msg->locked = FALSE; return TRUE; fail: _dbus_string_free (&tmp); if (!was_locked) msg->locked = FALSE; return FALSE; } /** * Demarshal a D-Bus message from the format described in the D-Bus * specification. * * Generally, this function is only useful for encapsulating D-Bus messages in * a different protocol. * * @param str the marshalled DBusMessage * @param len the length of str * @param error the location to save errors to * @returns #NULL if there was an error */ DBusMessage * dbus_message_demarshal (const char *str, int len, DBusError *error) { DBusMessageLoader *loader; DBusString *buffer; DBusMessage *msg; _dbus_return_val_if_fail (str != NULL, NULL); loader = _dbus_message_loader_new (); if (loader == NULL) return NULL; _dbus_message_loader_get_buffer (loader, &buffer); if (!_dbus_string_append_len (buffer, str, len)) goto fail_oom; _dbus_message_loader_return_buffer (loader, buffer); if (!_dbus_message_loader_queue_messages (loader)) goto fail_oom; if (_dbus_message_loader_get_is_corrupted (loader)) goto fail_corrupt; msg = _dbus_message_loader_pop_message (loader); if (!msg) goto fail_oom; _dbus_message_loader_unref (loader); return msg; fail_corrupt: dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Message is corrupted (%s)", _dbus_validity_to_error_message (loader->corruption_reason)); _dbus_message_loader_unref (loader); return NULL; fail_oom: _DBUS_SET_OOM (error); _dbus_message_loader_unref (loader); return NULL; } /** * Returns the number of bytes required to be in the buffer to demarshal a * D-Bus message. * * Generally, this function is only useful for encapsulating D-Bus messages in * a different protocol. * * @param buf data to be marshalled * @param len the length of @p buf * @returns -1 if there was no valid data to be demarshalled, 0 if there wasn't enough data to determine how much should be demarshalled. Otherwise returns the number of bytes to be demarshalled * */ int dbus_message_demarshal_bytes_needed(const char *buf, int len) { DBusString str; int byte_order, fields_array_len, header_len, body_len; DBusValidity validity = DBUS_VALID; int have_message; if (!buf || len < DBUS_MINIMUM_HEADER_SIZE) return 0; if (len > DBUS_MAXIMUM_MESSAGE_LENGTH) len = DBUS_MAXIMUM_MESSAGE_LENGTH; _dbus_string_init_const_len (&str, buf, len); validity = DBUS_VALID; have_message = _dbus_header_have_message_untrusted(DBUS_MAXIMUM_MESSAGE_LENGTH, &validity, &byte_order, &fields_array_len, &header_len, &body_len, &str, 0, len); _dbus_string_free (&str); if (validity == DBUS_VALID) { _dbus_assert (have_message || (header_len + body_len) > len); (void) have_message; /* unused unless asserting */ return header_len + body_len; } else { return -1; /* broken! */ } } /** * Sets a flag indicating that the caller of the method is prepared * to wait for interactive authorization to take place (for instance * via Polkit) before the actual method is processed. * * The flag is #FALSE by default; that is, by default the other end is * expected to make any authorization decisions non-interactively * and promptly. It may use the error * #DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED to signal that * authorization failed, but could have succeeded if this flag had * been used. * * For messages whose type is not #DBUS_MESSAGE_TYPE_METHOD_CALL, * this flag is meaningless and should not be set. * * On the protocol level this toggles * #DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION. * * @param message the message * @param allow #TRUE if interactive authorization is acceptable */ void dbus_message_set_allow_interactive_authorization (DBusMessage *message, dbus_bool_t allow) { _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); _dbus_header_toggle_flag (&message->header, DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION, allow); } /** * Returns whether the flag controlled by * dbus_message_set_allow_interactive_authorization() has been set. * * @param message the message */ dbus_bool_t dbus_message_get_allow_interactive_authorization (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, FALSE); return _dbus_header_get_flag (&message->header, DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION); } /** @} */ /* tests in dbus-message-util.c */ dbus-1.10.6/dbus/dbus-marshal-validate.h0000644000175000017500000002206712602773110020023 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-validate.h Validation routines for marshaled data * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MARSHAL_VALIDATE_H #define DBUS_MARSHAL_VALIDATE_H /** * @addtogroup DBusMarshal * * @{ */ /** * This is used rather than a bool for high visibility */ typedef enum { DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY, DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED } DBusValidationMode; /** * This is primarily used in unit testing, so we can verify that each * invalid message is invalid for the expected reasons. Thus we really * want a distinct enum value for every codepath leaving the validator * functions. Enum values are specified manually for ease of debugging * (so you can see the enum value given a printf) */ typedef enum { #define _DBUS_NEGATIVE_VALIDITY_COUNT 4 DBUS_VALIDITY_UNKNOWN_OOM_ERROR = -4, /**< can't determine validity due to OOM */ DBUS_INVALID_FOR_UNKNOWN_REASON = -3, DBUS_VALID_BUT_INCOMPLETE = -2, DBUS_VALIDITY_UNKNOWN = -1, DBUS_VALID = 0, /**< the data is valid */ DBUS_INVALID_UNKNOWN_TYPECODE = 1, DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE = 2, DBUS_INVALID_SIGNATURE_TOO_LONG = 3, /* this one is impossible right now since * you can't put a too-long value in a byte */ DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION = 4, DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION = 5, DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED = 6, DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED = 7, DBUS_INVALID_STRUCT_HAS_NO_FIELDS = 8, DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL = 9, DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE = 10, DBUS_INVALID_NOT_ENOUGH_DATA = 11, DBUS_INVALID_TOO_MUCH_DATA = 12, /**< trailing junk makes it invalid */ DBUS_INVALID_BAD_BYTE_ORDER = 13, DBUS_INVALID_BAD_PROTOCOL_VERSION = 14, DBUS_INVALID_BAD_MESSAGE_TYPE = 15, DBUS_INVALID_BAD_SERIAL = 16, DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH = 17, DBUS_INVALID_INSANE_BODY_LENGTH = 18, DBUS_INVALID_MESSAGE_TOO_LONG = 19, DBUS_INVALID_HEADER_FIELD_CODE = 20, DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE = 21, DBUS_INVALID_USES_LOCAL_INTERFACE = 22, DBUS_INVALID_USES_LOCAL_PATH = 23, DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE = 24, DBUS_INVALID_BAD_DESTINATION = 25, DBUS_INVALID_BAD_INTERFACE = 26, DBUS_INVALID_BAD_MEMBER = 27, DBUS_INVALID_BAD_ERROR_NAME = 28, DBUS_INVALID_BAD_SENDER = 29, DBUS_INVALID_MISSING_PATH = 30, DBUS_INVALID_MISSING_INTERFACE = 31, DBUS_INVALID_MISSING_MEMBER = 32, DBUS_INVALID_MISSING_ERROR_NAME = 33, DBUS_INVALID_MISSING_REPLY_SERIAL = 34, DBUS_INVALID_LENGTH_OUT_OF_BOUNDS = 35, DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM = 36, DBUS_INVALID_BAD_PATH = 37, DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 38, DBUS_INVALID_BAD_UTF8_IN_STRING = 39, DBUS_INVALID_ARRAY_LENGTH_INCORRECT = 40, DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 41, DBUS_INVALID_VARIANT_SIGNATURE_BAD = 42, DBUS_INVALID_VARIANT_SIGNATURE_EMPTY = 43, DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES = 44, DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL = 45, DBUS_INVALID_STRING_MISSING_NUL = 46, DBUS_INVALID_SIGNATURE_MISSING_NUL = 47, DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION = 48, DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED = 49, DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED = 50, DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS = 51, DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD = 52, DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS = 53, DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY = 54, DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE = 55, DBUS_INVALID_MISSING_UNIX_FDS = 56, DBUS_INVALID_NESTED_TOO_DEEPLY = 57, DBUS_VALIDITY_LAST } DBusValidity; DBUS_PRIVATE_EXPORT DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str, int type_pos, int len); DBUS_PRIVATE_EXPORT DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_signature, int expected_signature_start, int byte_order, int *bytes_remaining, const DBusString *value_str, int value_pos, int len); const char *_dbus_validity_to_error_message (DBusValidity validity); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_path (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_interface (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_member (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_error_name (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_bus_name (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_bus_namespace (const DBusString *str, int start, int len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_validate_signature (const DBusString *str, int start, int len); /* just to have a name consistent with the above: */ #define _dbus_validate_utf8(s,b,e) _dbus_string_validate_utf8 (s, b, e) #ifdef DBUS_DISABLE_CHECKS /* Be sure they don't exist, since we don't want to use them outside of checks * and so we want the compile failure. */ #define DECLARE_DBUS_NAME_CHECK(what) #define DEFINE_DBUS_NAME_CHECK(what) #else /* !DBUS_DISABLE_CHECKS */ /** A name check is used in _dbus_return_if_fail(), it's not suitable * for validating untrusted data. use _dbus_validate_whatever for that. */ #define DECLARE_DBUS_NAME_CHECK(what) \ dbus_bool_t _dbus_check_is_valid_##what (const char *name) /** Define a name check to be used in _dbus_return_if_fail() statements. */ #define DEFINE_DBUS_NAME_CHECK(what) \ dbus_bool_t \ _dbus_check_is_valid_##what (const char *name) \ { \ DBusString str; \ \ if (name == NULL) \ return FALSE; \ \ _dbus_string_init_const (&str, name); \ return _dbus_validate_##what (&str, 0, \ _dbus_string_get_length (&str)); \ } #endif /* !DBUS_DISABLE_CHECKS */ /** defines _dbus_check_is_valid_path() */ DECLARE_DBUS_NAME_CHECK(path); /** defines _dbus_check_is_valid_interface() */ DECLARE_DBUS_NAME_CHECK(interface); /** defines _dbus_check_is_valid_member() */ DECLARE_DBUS_NAME_CHECK(member); /** defines _dbus_check_is_valid_error_name() */ DECLARE_DBUS_NAME_CHECK(error_name); /** defines _dbus_check_is_valid_bus_name() */ DECLARE_DBUS_NAME_CHECK(bus_name); /** defines _dbus_check_is_valid_signature() */ DECLARE_DBUS_NAME_CHECK(signature); /** defines _dbus_check_is_valid_utf8() */ DECLARE_DBUS_NAME_CHECK(utf8); /** @} */ #endif /* DBUS_MARSHAL_VALIDATE_H */ dbus-1.10.6/dbus/dbus-marshal-validate.c0000644000175000017500000012146112624705346020026 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-validate.c Validation routines for marshaled data * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-internals.h" #include "dbus-marshal-validate.h" #include "dbus-marshal-recursive.h" #include "dbus-marshal-basic.h" #include "dbus-signature.h" #include "dbus-string.h" /** * @addtogroup DBusMarshal * * @{ */ /** * Verifies that the range of type_str from type_pos to type_end is a * valid signature. If this function returns #TRUE, it will be safe * to iterate over the signature with a types-only #DBusTypeReader. * The range passed in should NOT include the terminating * nul/DBUS_TYPE_INVALID. * * @param type_str the string * @param type_pos where the typecodes start * @param len length of typecodes * @returns #DBUS_VALID if valid, reason why invalid otherwise */ DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str, int type_pos, int len) { const unsigned char *p; const unsigned char *end; int last; int struct_depth; int array_depth; int dict_entry_depth; DBusValidity result; int element_count; DBusList *element_count_stack; result = DBUS_VALID; element_count_stack = NULL; if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } _dbus_assert (type_str != NULL); _dbus_assert (type_pos < _DBUS_INT32_MAX - len); _dbus_assert (len >= 0); _dbus_assert (type_pos >= 0); if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH) { result = DBUS_INVALID_SIGNATURE_TOO_LONG; goto out; } p = _dbus_string_get_const_data_len (type_str, type_pos, 0); end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0); struct_depth = 0; array_depth = 0; dict_entry_depth = 0; last = DBUS_TYPE_INVALID; while (p != end) { switch (*p) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: case DBUS_TYPE_VARIANT: break; case DBUS_TYPE_ARRAY: array_depth += 1; if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; goto out; } break; case DBUS_STRUCT_BEGIN_CHAR: struct_depth += 1; if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; goto out; } if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } break; case DBUS_STRUCT_END_CHAR: if (struct_depth == 0) { result = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; goto out; } if (last == DBUS_STRUCT_BEGIN_CHAR) { result = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; goto out; } _dbus_list_pop_last (&element_count_stack); struct_depth -= 1; break; case DBUS_DICT_ENTRY_BEGIN_CHAR: if (last != DBUS_TYPE_ARRAY) { result = DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY; goto out; } dict_entry_depth += 1; if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; goto out; } if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } break; case DBUS_DICT_ENTRY_END_CHAR: if (dict_entry_depth == 0) { result = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; goto out; } dict_entry_depth -= 1; element_count = _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); if (element_count != 2) { if (element_count == 0) result = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; else if (element_count == 1) result = DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD; else result = DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS; goto out; } break; case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */ case DBUS_TYPE_DICT_ENTRY: /* ditto */ default: result = DBUS_INVALID_UNKNOWN_TYPECODE; goto out; } if (*p != DBUS_TYPE_ARRAY && *p != DBUS_DICT_ENTRY_BEGIN_CHAR && *p != DBUS_STRUCT_BEGIN_CHAR) { element_count = _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); ++element_count; if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (element_count))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } } if (array_depth > 0) { if (*p == DBUS_TYPE_ARRAY && p != end) { const char *p1; p1 = p + 1; if (*p1 == DBUS_STRUCT_END_CHAR || *p1 == DBUS_DICT_ENTRY_END_CHAR) { result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; goto out; } } else { array_depth = 0; } } if (last == DBUS_DICT_ENTRY_BEGIN_CHAR) { if (!(dbus_type_is_valid (*p) && dbus_type_is_basic (*p))) { result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE; goto out; } } last = *p; ++p; } if (array_depth > 0) { result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; goto out; } if (struct_depth > 0) { result = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; goto out; } if (dict_entry_depth > 0) { result = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; goto out; } _dbus_assert (last != DBUS_TYPE_ARRAY); _dbus_assert (last != DBUS_STRUCT_BEGIN_CHAR); _dbus_assert (last != DBUS_DICT_ENTRY_BEGIN_CHAR); result = DBUS_VALID; out: _dbus_list_clear (&element_count_stack); return result; } /* note: this function is also used to validate the header's values, * since the header is a valid body with a particular signature. */ static DBusValidity validate_body_helper (DBusTypeReader *reader, int byte_order, dbus_bool_t walk_reader_to_end, int total_depth, const unsigned char *p, const unsigned char *end, const unsigned char **new_p) { int current_type; /* The spec allows arrays and structs to each nest 32, for total * nesting of 2*32. We want to impose the same limit on "dynamic" * value nesting (not visible in the signature) which is introduced * by DBUS_TYPE_VARIANT. */ if (total_depth > (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH * 2)) { return DBUS_INVALID_NESTED_TOO_DEEPLY; } while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) { const unsigned char *a; int alignment; #if 0 _dbus_verbose (" validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n", _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, (int) (end - p)); #endif /* Guarantee that p has one byte to look at */ if (p == end) return DBUS_INVALID_NOT_ENOUGH_DATA; switch (current_type) { case DBUS_TYPE_BYTE: ++p; break; case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: case DBUS_TYPE_UNIX_FD: case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: alignment = _dbus_type_get_alignment (current_type); a = _DBUS_ALIGN_ADDRESS (p, alignment); if (a >= end) return DBUS_INVALID_NOT_ENOUGH_DATA; while (p != a) { if (*p != '\0') return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; ++p; } if (current_type == DBUS_TYPE_BOOLEAN) { dbus_uint32_t v = _dbus_unpack_uint32 (byte_order, p); if (!(v == 0 || v == 1)) return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE; } p += alignment; break; case DBUS_TYPE_ARRAY: case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: { dbus_uint32_t claimed_len; a = _DBUS_ALIGN_ADDRESS (p, 4); if (a + 4 > end) return DBUS_INVALID_NOT_ENOUGH_DATA; while (p != a) { if (*p != '\0') return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; ++p; } claimed_len = _dbus_unpack_uint32 (byte_order, p); p += 4; /* p may now be == end */ _dbus_assert (p <= end); if (current_type == DBUS_TYPE_ARRAY) { int array_elem_type = _dbus_type_reader_get_element_type (reader); if (!dbus_type_is_valid (array_elem_type)) { return DBUS_INVALID_UNKNOWN_TYPECODE; } alignment = _dbus_type_get_alignment (array_elem_type); a = _DBUS_ALIGN_ADDRESS (p, alignment); /* a may now be == end */ if (a > end) return DBUS_INVALID_NOT_ENOUGH_DATA; while (p != a) { if (*p != '\0') return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; ++p; } } if (claimed_len > (unsigned long) (end - p)) return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS; if (current_type == DBUS_TYPE_OBJECT_PATH) { DBusString str; _dbus_string_init_const_len (&str, p, claimed_len); if (!_dbus_validate_path (&str, 0, _dbus_string_get_length (&str))) return DBUS_INVALID_BAD_PATH; p += claimed_len; } else if (current_type == DBUS_TYPE_STRING) { DBusString str; _dbus_string_init_const_len (&str, p, claimed_len); if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str))) return DBUS_INVALID_BAD_UTF8_IN_STRING; p += claimed_len; } else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0) { DBusTypeReader sub; DBusValidity validity; const unsigned char *array_end; int array_elem_type; if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH) return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM; /* Remember that the reader is types only, so we can't * use it to iterate over elements. It stays the same * for all elements. */ _dbus_type_reader_recurse (reader, &sub); array_end = p + claimed_len; array_elem_type = _dbus_type_reader_get_element_type (reader); /* avoid recursive call to validate_body_helper if this is an array * of fixed-size elements */ if (dbus_type_is_fixed (array_elem_type)) { /* bools need to be handled differently, because they can * have an invalid value */ if (array_elem_type == DBUS_TYPE_BOOLEAN) { dbus_uint32_t v; alignment = _dbus_type_get_alignment (array_elem_type); while (p < array_end) { v = _dbus_unpack_uint32 (byte_order, p); if (!(v == 0 || v == 1)) return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE; p += alignment; } } else { p = array_end; } } else { while (p < array_end) { validity = validate_body_helper (&sub, byte_order, FALSE, total_depth + 1, p, end, &p); if (validity != DBUS_VALID) return validity; } } if (p != array_end) return DBUS_INVALID_ARRAY_LENGTH_INCORRECT; } /* check nul termination */ if (current_type != DBUS_TYPE_ARRAY) { if (p == end) return DBUS_INVALID_NOT_ENOUGH_DATA; if (*p != '\0') return DBUS_INVALID_STRING_MISSING_NUL; ++p; } } break; case DBUS_TYPE_SIGNATURE: { dbus_uint32_t claimed_len; DBusString str; DBusValidity validity; claimed_len = *p; ++p; /* 1 is for nul termination */ if (claimed_len + 1 > (unsigned long) (end - p)) return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS; _dbus_string_init_const_len (&str, p, claimed_len); validity = _dbus_validate_signature_with_reason (&str, 0, _dbus_string_get_length (&str)); if (validity != DBUS_VALID) return validity; p += claimed_len; _dbus_assert (p < end); if (*p != DBUS_TYPE_INVALID) return DBUS_INVALID_SIGNATURE_MISSING_NUL; ++p; _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len); } break; case DBUS_TYPE_VARIANT: { /* 1 byte sig len, sig typecodes, align to * contained-type-boundary, values. */ /* In addition to normal signature validation, we need to be sure * the signature contains only a single (possibly container) type. */ dbus_uint32_t claimed_len; DBusString sig; DBusTypeReader sub; DBusValidity validity; int contained_alignment; int contained_type; DBusValidity reason; claimed_len = *p; ++p; /* + 1 for nul */ if (claimed_len + 1 > (unsigned long) (end - p)) return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS; _dbus_string_init_const_len (&sig, p, claimed_len); reason = _dbus_validate_signature_with_reason (&sig, 0, _dbus_string_get_length (&sig)); if (!(reason == DBUS_VALID)) { if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR) return reason; else return DBUS_INVALID_VARIANT_SIGNATURE_BAD; } p += claimed_len; if (*p != DBUS_TYPE_INVALID) return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL; ++p; contained_type = _dbus_first_type_in_signature (&sig, 0); if (contained_type == DBUS_TYPE_INVALID) return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY; contained_alignment = _dbus_type_get_alignment (contained_type); a = _DBUS_ALIGN_ADDRESS (p, contained_alignment); if (a > end) return DBUS_INVALID_NOT_ENOUGH_DATA; while (p != a) { if (*p != '\0') return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; ++p; } _dbus_type_reader_init_types_only (&sub, &sig, 0); _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID); validity = validate_body_helper (&sub, byte_order, FALSE, total_depth + 1, p, end, &p); if (validity != DBUS_VALID) return validity; if (_dbus_type_reader_next (&sub)) return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES; _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID); } break; case DBUS_TYPE_DICT_ENTRY: case DBUS_TYPE_STRUCT: { DBusTypeReader sub; DBusValidity validity; a = _DBUS_ALIGN_ADDRESS (p, 8); if (a > end) return DBUS_INVALID_NOT_ENOUGH_DATA; while (p != a) { if (*p != '\0') return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; ++p; } _dbus_type_reader_recurse (reader, &sub); validity = validate_body_helper (&sub, byte_order, TRUE, total_depth + 1, p, end, &p); if (validity != DBUS_VALID) return validity; } break; default: _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); break; } #if 0 _dbus_verbose (" validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n", _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, (int) (end - p)); #endif if (p > end) { _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n", p, end, (int) (end - p)); return DBUS_INVALID_NOT_ENOUGH_DATA; } if (walk_reader_to_end) _dbus_type_reader_next (reader); else break; } if (new_p) *new_p = p; return DBUS_VALID; } /** * Verifies that the range of value_str from value_pos to value_end is * a legitimate value of type expected_signature. If this function * returns #TRUE, it will be safe to iterate over the values with * #DBusTypeReader. The signature is assumed to be already valid. * * If bytes_remaining is not #NULL, then leftover bytes will be stored * there and #DBUS_VALID returned. If it is #NULL, then * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left * over. * * @param expected_signature the expected types in the value_str * @param expected_signature_start where in expected_signature is the signature * @param byte_order the byte order * @param bytes_remaining place to store leftover bytes * @param value_str the string containing the body * @param value_pos where the values start * @param len length of values after value_pos * @returns #DBUS_VALID if valid, reason why invalid otherwise */ DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_signature, int expected_signature_start, int byte_order, int *bytes_remaining, const DBusString *value_str, int value_pos, int len) { DBusTypeReader reader; const unsigned char *p; const unsigned char *end; DBusValidity validity; _dbus_assert (len >= 0); _dbus_assert (value_pos >= 0); _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len); _dbus_verbose ("validating body from pos %d len %d sig '%s'\n", value_pos, len, _dbus_string_get_const_data_len (expected_signature, expected_signature_start, 0)); _dbus_type_reader_init_types_only (&reader, expected_signature, expected_signature_start); p = _dbus_string_get_const_data_len (value_str, value_pos, len); end = p + len; validity = validate_body_helper (&reader, byte_order, TRUE, 0, p, end, &p); if (validity != DBUS_VALID) return validity; if (bytes_remaining) { *bytes_remaining = end - p; return DBUS_VALID; } else if (p < end) return DBUS_INVALID_TOO_MUCH_DATA; else { _dbus_assert (p == end); return DBUS_VALID; } } /** * Determine wether the given character is valid as the first character * in a name. */ #define VALID_INITIAL_NAME_CHARACTER(c) \ ( ((c) >= 'A' && (c) <= 'Z') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) == '_') ) /** * Determine wether the given character is valid as a second or later * character in a name */ #define VALID_NAME_CHARACTER(c) \ ( ((c) >= '0' && (c) <= '9') || \ ((c) >= 'A' && (c) <= 'Z') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) == '_') ) /** * Checks that the given range of the string is a valid object path * name in the D-Bus protocol. Part of the validation ensures that * the object path contains only ASCII. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @todo change spec to disallow more things, such as spaces in the * path name * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_path (const DBusString *str, int start, int len) { const unsigned char *s; const unsigned char *end; const unsigned char *last_slash; _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= _dbus_string_get_length (str)); if (len > _dbus_string_get_length (str) - start) return FALSE; if (len == 0) return FALSE; s = _dbus_string_get_const_data (str) + start; end = s + len; if (*s != '/') return FALSE; last_slash = s; ++s; while (s != end) { if (*s == '/') { if ((s - last_slash) < 2) return FALSE; /* no empty path components allowed */ last_slash = s; } else { if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) return FALSE; } ++s; } if ((end - last_slash) < 2 && len > 1) return FALSE; /* trailing slash not allowed unless the string is "/" */ return TRUE; } const char * _dbus_validity_to_error_message (DBusValidity validity) { switch (validity) { case DBUS_VALIDITY_UNKNOWN_OOM_ERROR: return "Out of memory"; case DBUS_INVALID_FOR_UNKNOWN_REASON: return "Unknown reason"; case DBUS_VALID_BUT_INCOMPLETE: return "Valid but incomplete"; case DBUS_VALIDITY_UNKNOWN: return "Validity unknown"; case DBUS_VALID: return "Valid"; case DBUS_INVALID_UNKNOWN_TYPECODE: return "Unknown typecode"; case DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE: return "Missing array element type"; case DBUS_INVALID_SIGNATURE_TOO_LONG: return "Signature is too long"; case DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION: return "Exceeded maximum array recursion"; case DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION: return "Exceeded maximum struct recursion"; case DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED: return "Struct ended but not started"; case DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED: return "Struct started but not ended"; case DBUS_INVALID_STRUCT_HAS_NO_FIELDS: return "Struct has no fields"; case DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL: return "Alignment padding not null"; case DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE: return "Boolean is not zero or one"; case DBUS_INVALID_NOT_ENOUGH_DATA: return "Not enough data"; case DBUS_INVALID_TOO_MUCH_DATA: return "Too much data"; case DBUS_INVALID_BAD_BYTE_ORDER: return "Bad byte order"; case DBUS_INVALID_BAD_PROTOCOL_VERSION: return "Bad protocol version"; case DBUS_INVALID_BAD_MESSAGE_TYPE: return "Bad message type"; case DBUS_INVALID_BAD_SERIAL: return "Bad serial"; case DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH: return "Insane fields array length"; case DBUS_INVALID_INSANE_BODY_LENGTH: return "Insane body length"; case DBUS_INVALID_MESSAGE_TOO_LONG: return "Message too long"; case DBUS_INVALID_HEADER_FIELD_CODE: return "Header field code"; case DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE: return "Header field has wrong type"; case DBUS_INVALID_USES_LOCAL_INTERFACE: return "Uses local interface"; case DBUS_INVALID_USES_LOCAL_PATH: return "Uses local path"; case DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE: return "Header field appears twice"; case DBUS_INVALID_BAD_DESTINATION: return "Bad destination"; case DBUS_INVALID_BAD_INTERFACE: return "Bad interface"; case DBUS_INVALID_BAD_MEMBER: return "Bad member"; case DBUS_INVALID_BAD_ERROR_NAME: return "Bad error name"; case DBUS_INVALID_BAD_SENDER: return "Bad sender"; case DBUS_INVALID_MISSING_PATH: return "Missing path"; case DBUS_INVALID_MISSING_INTERFACE: return "Missing interface"; case DBUS_INVALID_MISSING_MEMBER: return "Missing member"; case DBUS_INVALID_MISSING_ERROR_NAME: return "Missing error name"; case DBUS_INVALID_MISSING_REPLY_SERIAL: return "Missing reply serial"; case DBUS_INVALID_LENGTH_OUT_OF_BOUNDS: return "Length out of bounds"; case DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM: return "Array length exceeds maximum"; case DBUS_INVALID_BAD_PATH: return "Bad path"; case DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Signature length out of bounds"; case DBUS_INVALID_BAD_UTF8_IN_STRING: return "Bad utf8 in string"; case DBUS_INVALID_ARRAY_LENGTH_INCORRECT: return "Array length incorrect"; case DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Variant signature length out of bounds"; case DBUS_INVALID_VARIANT_SIGNATURE_BAD: return "Variant signature bad"; case DBUS_INVALID_VARIANT_SIGNATURE_EMPTY: return "Variant signature empty"; case DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES: return "Variant signature specifies multiple values"; case DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL: return "Variant signature missing nul"; case DBUS_INVALID_STRING_MISSING_NUL: return "String missing nul"; case DBUS_INVALID_SIGNATURE_MISSING_NUL: return "Signature missing nul"; case DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION: return "Exceeded maximum dict entry recursion"; case DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED: return "Dict entry ended but not started"; case DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED: return "Dict entry started but not ended"; case DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS: return "Dict entry has no fields"; case DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD: return "Dict entry has only one field"; case DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS: return "Dict entry has too many fields"; case DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY: return "Dict entry not inside array"; case DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE: return "Dict key must be basic type"; case DBUS_INVALID_NESTED_TOO_DEEPLY: return "Variants cannot be used to create a hugely recursive tree of values"; default: return "Invalid"; } } /** * Checks that the given range of the string is a valid interface name * in the D-Bus protocol. This includes a length restriction and an * ASCII subset, see the specification. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_interface (const DBusString *str, int start, int len) { const unsigned char *s; const unsigned char *end; const unsigned char *iface; const unsigned char *last_dot; _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= _dbus_string_get_length (str)); if (len > _dbus_string_get_length (str) - start) return FALSE; if (len > DBUS_MAXIMUM_NAME_LENGTH) return FALSE; if (len == 0) return FALSE; last_dot = NULL; iface = _dbus_string_get_const_data (str) + start; end = iface + len; s = iface; /* check special cases of first char so it doesn't have to be done * in the loop. Note we know len > 0 */ if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ return FALSE; else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) return FALSE; else ++s; while (s != end) { if (*s == '.') { if (_DBUS_UNLIKELY ((s + 1) == end)) return FALSE; else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1)))) return FALSE; last_dot = s; ++s; /* we just validated the next char, so skip two */ } else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) { return FALSE; } ++s; } if (_DBUS_UNLIKELY (last_dot == NULL)) return FALSE; return TRUE; } /** * Checks that the given range of the string is a valid member name * in the D-Bus protocol. This includes a length restriction, etc., * see the specification. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_member (const DBusString *str, int start, int len) { const unsigned char *s; const unsigned char *end; const unsigned char *member; _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= _dbus_string_get_length (str)); if (len > _dbus_string_get_length (str) - start) return FALSE; if (len > DBUS_MAXIMUM_NAME_LENGTH) return FALSE; if (len == 0) return FALSE; member = _dbus_string_get_const_data (str) + start; end = member + len; s = member; /* check special cases of first char so it doesn't have to be done * in the loop. Note we know len > 0 */ if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) return FALSE; else ++s; while (s != end) { if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) { return FALSE; } ++s; } return TRUE; } /** * Checks that the given range of the string is a valid error name * in the D-Bus protocol. This includes a length restriction, etc., * see the specification. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_error_name (const DBusString *str, int start, int len) { /* Same restrictions as interface name at the moment */ return _dbus_validate_interface (str, start, len); } /** * Determine wether the given character is valid as the first character * in a bus name. */ #define VALID_INITIAL_BUS_NAME_CHARACTER(c) \ ( ((c) >= 'A' && (c) <= 'Z') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) == '_') || ((c) == '-')) /** * Determine wether the given character is valid as a second or later * character in a bus name */ #define VALID_BUS_NAME_CHARACTER(c) \ ( ((c) >= '0' && (c) <= '9') || \ ((c) >= 'A' && (c) <= 'Z') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) == '_') || ((c) == '-')) static dbus_bool_t _dbus_validate_bus_name_full (const DBusString *str, int start, int len, dbus_bool_t is_namespace) { const unsigned char *s; const unsigned char *end; const unsigned char *iface; const unsigned char *last_dot; _dbus_assert (start >= 0); _dbus_assert (len >= 0); _dbus_assert (start <= _dbus_string_get_length (str)); if (len > _dbus_string_get_length (str) - start) return FALSE; if (len > DBUS_MAXIMUM_NAME_LENGTH) return FALSE; if (len == 0) return FALSE; last_dot = NULL; iface = _dbus_string_get_const_data (str) + start; end = iface + len; s = iface; /* check special cases of first char so it doesn't have to be done * in the loop. Note we know len > 0 */ if (*s == ':') { /* unique name */ ++s; while (s != end) { if (*s == '.') { if (_DBUS_UNLIKELY ((s + 1) == end)) return FALSE; if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*(s + 1)))) return FALSE; ++s; /* we just validated the next char, so skip two */ } else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s))) { return FALSE; } ++s; } return TRUE; } else if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ return FALSE; else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*s))) return FALSE; else ++s; while (s != end) { if (*s == '.') { if (_DBUS_UNLIKELY ((s + 1) == end)) return FALSE; else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*(s + 1)))) return FALSE; last_dot = s; ++s; /* we just validated the next char, so skip two */ } else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s))) { return FALSE; } ++s; } if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL)) return FALSE; return TRUE; } /** * Checks that the given range of the string is a valid bus name in * the D-Bus protocol. This includes a length restriction, etc., see * the specification. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_bus_name (const DBusString *str, int start, int len) { return _dbus_validate_bus_name_full (str, start, len, FALSE); } /** * Checks that the given range of the string is a prefix of a valid bus name in * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings * with only one period-separated component. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t _dbus_validate_bus_namespace (const DBusString *str, int start, int len) { return _dbus_validate_bus_name_full (str, start, len, TRUE); } /** * Checks that the given range of the string is a valid message type * signature in the D-Bus protocol. * * @todo this is inconsistent with most of DBusString in that * it allows a start,len range that extends past the string end. * * @param str the string * @param start first byte index to check * @param len number of bytes to check * @returns #TRUE if the byte range exists and is a valid signature */ dbus_bool_t _dbus_validate_signature (const DBusString *str, int start, int len) { _dbus_assert (start >= 0); _dbus_assert (start <= _dbus_string_get_length (str)); _dbus_assert (len >= 0); if (len > _dbus_string_get_length (str) - start) return FALSE; return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID; } /** define _dbus_check_is_valid_path() */ DEFINE_DBUS_NAME_CHECK(path) /** define _dbus_check_is_valid_interface() */ DEFINE_DBUS_NAME_CHECK(interface) /** define _dbus_check_is_valid_member() */ DEFINE_DBUS_NAME_CHECK(member) /** define _dbus_check_is_valid_error_name() */ DEFINE_DBUS_NAME_CHECK(error_name) /** define _dbus_check_is_valid_bus_name() */ DEFINE_DBUS_NAME_CHECK(bus_name) /** define _dbus_check_is_valid_signature() */ DEFINE_DBUS_NAME_CHECK(signature) /** define _dbus_check_is_valid_utf8() */ DEFINE_DBUS_NAME_CHECK(utf8) /** @} */ /* tests in dbus-marshal-validate-util.c */ dbus-1.10.6/dbus/dbus-marshal-recursive.h0000644000175000017500000002474512602773110020246 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-recursive.h Marshalling routines for recursive types * * Copyright (C) 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MARSHAL_RECURSIVE_H #define DBUS_MARSHAL_RECURSIVE_H #include #include typedef struct DBusTypeReader DBusTypeReader; typedef struct DBusTypeWriter DBusTypeWriter; typedef struct DBusTypeReaderClass DBusTypeReaderClass; typedef struct DBusArrayLenFixup DBusArrayLenFixup; /** * The type reader is an iterator for reading values from a block of * values. */ struct DBusTypeReader { dbus_uint32_t byte_order : 8; /**< byte order of the block */ dbus_uint32_t finished : 1; /**< marks we're at end iterator for cases * where we don't have another way to tell */ dbus_uint32_t array_len_offset : 3; /**< bytes back from start_pos that len ends */ const DBusString *type_str; /**< string containing signature of block */ int type_pos; /**< current position in signature */ const DBusString *value_str; /**< string containing values of block */ int value_pos; /**< current position in values */ const DBusTypeReaderClass *klass; /**< the vtable for the reader */ union { struct { int start_pos; /**< for array readers, the start of the array values */ } array; } u; /**< class-specific data */ }; /** * The type writer is an iterator for writing to a block of values. */ struct DBusTypeWriter { dbus_uint32_t byte_order : 8; /**< byte order to write values with */ dbus_uint32_t container_type : 8; /**< what are we inside? (e.g. struct, variant, array) */ dbus_uint32_t type_pos_is_expectation : 1; /**< type_pos can be either an insertion point for or an expected next type */ dbus_uint32_t enabled : 1; /**< whether to write values */ DBusString *type_str; /**< where to write typecodes (or read type expectations) */ int type_pos; /**< current pos in type_str */ DBusString *value_str; /**< where to write values */ int value_pos; /**< next position to write */ union { struct { int start_pos; /**< position of first element in the array */ int len_pos; /**< position of length of the array */ int element_type_pos; /**< position of array element type in type_str */ } array; } u; /**< class-specific data */ }; /** * When modifying an existing block of values, array lengths may need * to be adjusted; those adjustments are described by this struct. */ struct DBusArrayLenFixup { int len_pos_in_reader; /**< where the length was in the original block */ int new_len; /**< the new value of the length in the written-out block */ }; DBUS_PRIVATE_EXPORT void _dbus_type_reader_init (DBusTypeReader *reader, int byte_order, const DBusString *type_str, int type_pos, const DBusString *value_str, int value_pos); DBUS_PRIVATE_EXPORT void _dbus_type_reader_init_types_only (DBusTypeReader *reader, const DBusString *type_str, int type_pos); DBUS_PRIVATE_EXPORT int _dbus_type_reader_get_current_type (const DBusTypeReader *reader); DBUS_PRIVATE_EXPORT int _dbus_type_reader_get_element_type (const DBusTypeReader *reader); int _dbus_type_reader_get_value_pos (const DBusTypeReader *reader); DBUS_PRIVATE_EXPORT void _dbus_type_reader_read_basic (const DBusTypeReader *reader, void *value); int _dbus_type_reader_get_array_length (const DBusTypeReader *reader); DBUS_PRIVATE_EXPORT void _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, void *value, int *n_elements); void _dbus_type_reader_read_raw (const DBusTypeReader *reader, const unsigned char **value_location); DBUS_PRIVATE_EXPORT void _dbus_type_reader_recurse (DBusTypeReader *reader, DBusTypeReader *subreader); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader); dbus_bool_t _dbus_type_reader_has_next (const DBusTypeReader *reader); DBUS_PRIVATE_EXPORT void _dbus_type_reader_get_signature (const DBusTypeReader *reader, const DBusString **str_p, int *start_p, int *len_p); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_reader_set_basic (DBusTypeReader *reader, const void *value, const DBusTypeReader *realign_root); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_reader_delete (DBusTypeReader *reader, const DBusTypeReader *realign_root); dbus_bool_t _dbus_type_reader_equal_values (const DBusTypeReader *lhs, const DBusTypeReader *rhs); void _dbus_type_signature_next (const char *signature, int *type_pos); DBUS_PRIVATE_EXPORT void _dbus_type_writer_init (DBusTypeWriter *writer, int byte_order, DBusString *type_str, int type_pos, DBusString *value_str, int value_pos); void _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, int byte_order, DBusString *value_str, int value_pos); void _dbus_type_writer_add_types (DBusTypeWriter *writer, DBusString *type_str, int type_pos); void _dbus_type_writer_remove_types (DBusTypeWriter *writer); DBUS_PRIVATE_EXPORT void _dbus_type_writer_init_values_only (DBusTypeWriter *writer, int byte_order, const DBusString *type_str, int type_pos, DBusString *value_str, int value_pos); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer, int type, const void *value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, int element_type, const void *value, int n_elements); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer, int container_type, const DBusString *contained_type, int contained_type_start, DBusTypeWriter *sub); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_writer_unrecurse (DBusTypeWriter *writer, DBusTypeWriter *sub); dbus_bool_t _dbus_type_writer_append_array (DBusTypeWriter *writer, const DBusString *contained_type, int contained_type_start, DBusTypeWriter *sub); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_type_writer_write_reader (DBusTypeWriter *writer, DBusTypeReader *reader); #endif /* DBUS_MARSHAL_RECURSIVE_H */ dbus-1.10.6/dbus/dbus-marshal-recursive.c0000644000175000017500000027335212602773110020241 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-recursive.c Marshalling routines for recursive types * * Copyright (C) 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-marshal-recursive.h" #include "dbus-marshal-basic.h" #include "dbus-signature.h" #include "dbus-internals.h" /** * @addtogroup DBusMarshal * @{ */ static dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs, const DBusTypeReader *rhs); static void _dbus_type_writer_set_enabled (DBusTypeWriter *writer, dbus_bool_t enabled); static dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, DBusTypeReader *reader, const DBusTypeReader *start_after, int start_after_new_pos, int start_after_new_len, DBusList **fixups); /** turn this on to get deluged in TypeReader verbose spam */ #define RECURSIVE_MARSHAL_READ_TRACE 0 /** turn this on to get deluged in TypeWriter verbose spam */ #define RECURSIVE_MARSHAL_WRITE_TRACE 0 static void free_fixups (DBusList **fixups) { DBusList *link; link = _dbus_list_get_first_link (fixups); while (link != NULL) { DBusList *next; next = _dbus_list_get_next_link (fixups, link); dbus_free (link->data); _dbus_list_free_link (link); link = next; } *fixups = NULL; } static void apply_and_free_fixups (DBusList **fixups, DBusTypeReader *reader) { DBusList *link; #if RECURSIVE_MARSHAL_WRITE_TRACE if (*fixups) _dbus_verbose (" %d FIXUPS to apply\n", _dbus_list_get_length (fixups)); #endif link = _dbus_list_get_first_link (fixups); while (link != NULL) { DBusList *next; next = _dbus_list_get_next_link (fixups, link); if (reader) { DBusArrayLenFixup *f; f = link->data; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n", reader, f->len_pos_in_reader, f->new_len, _dbus_marshal_read_uint32 (reader->value_str, f->len_pos_in_reader, reader->byte_order, NULL)); #endif _dbus_marshal_set_uint32 ((DBusString*) reader->value_str, f->len_pos_in_reader, f->new_len, reader->byte_order); } dbus_free (link->data); _dbus_list_free_link (link); link = next; } *fixups = NULL; } /** * Virtual table for a type reader. */ struct DBusTypeReaderClass { const char *name; /**< name for debugging */ int id; /**< index in all_reader_classes */ dbus_bool_t types_only; /**< only iterates over types, not values */ void (* recurse) (DBusTypeReader *sub, DBusTypeReader *parent); /**< recurse with this reader as sub */ dbus_bool_t (* check_finished) (const DBusTypeReader *reader); /**< check whether reader is at the end */ void (* next) (DBusTypeReader *reader, int current_type); /**< go to the next value */ }; static int element_type_get_alignment (const DBusString *str, int pos) { return _dbus_type_get_alignment (_dbus_first_type_in_signature (str, pos)); } static void reader_init (DBusTypeReader *reader, int byte_order, const DBusString *type_str, int type_pos, const DBusString *value_str, int value_pos) { _DBUS_ZERO (*reader); reader->byte_order = byte_order; reader->finished = FALSE; reader->type_str = type_str; reader->type_pos = type_pos; reader->value_str = value_str; reader->value_pos = value_pos; } static void base_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { /* point subreader at the same place as parent */ reader_init (sub, parent->byte_order, parent->type_str, parent->type_pos, parent->value_str, parent->value_pos); } static void struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { base_reader_recurse (sub, parent); _dbus_assert (_dbus_string_get_byte (sub->type_str, sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR || _dbus_string_get_byte (sub->type_str, sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR); sub->type_pos += 1; } static void struct_or_dict_entry_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { struct_or_dict_entry_types_only_reader_recurse (sub, parent); /* struct and dict entry have 8 byte alignment */ sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); } static void array_types_only_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { base_reader_recurse (sub, parent); /* point type_pos at the array element type */ sub->type_pos += 1; /* Init with values likely to crash things if misused */ sub->u.array.start_pos = _DBUS_INT_MAX; sub->array_len_offset = 7; } /** compute position of array length given array_len_offset, which is the offset back from start_pos to end of the len */ #define ARRAY_READER_LEN_POS(reader) \ ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4) static int array_reader_get_array_len (const DBusTypeReader *reader) { dbus_uint32_t array_len; int len_pos; len_pos = ARRAY_READER_LEN_POS (reader); _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos); array_len = _dbus_unpack_uint32 (reader->byte_order, _dbus_string_get_const_data_len (reader->value_str, len_pos, 4)); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n", reader, len_pos, array_len, reader->array_len_offset); #endif _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8); return array_len; } static void array_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { int alignment; int len_pos; array_types_only_reader_recurse (sub, parent); sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); len_pos = sub->value_pos; sub->value_pos += 4; /* for the length */ alignment = element_type_get_alignment (sub->type_str, sub->type_pos); sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); sub->u.array.start_pos = sub->value_pos; _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */ sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n", sub, sub->u.array.start_pos, sub->array_len_offset, array_reader_get_array_len (sub), _dbus_type_to_string (_dbus_first_type_in_signature (sub->type_str, sub->type_pos))); #endif } static void variant_reader_recurse (DBusTypeReader *sub, DBusTypeReader *parent) { int sig_len; int contained_alignment; base_reader_recurse (sub, parent); /* Variant is 1 byte sig length (without nul), signature with nul, * padding to 8-boundary, then values */ sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos); sub->type_str = sub->value_str; sub->type_pos = sub->value_pos + 1; sub->value_pos = sub->type_pos + sig_len + 1; contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (sub->type_str, sub->type_pos)); sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p variant containing '%s'\n", sub, _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0)); #endif } static dbus_bool_t array_reader_check_finished (const DBusTypeReader *reader) { int end_pos; /* return the array element type if elements remain, and * TYPE_INVALID otherwise */ end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); _dbus_assert (reader->value_pos <= end_pos); _dbus_assert (reader->value_pos >= reader->u.array.start_pos); return reader->value_pos == end_pos; } static void skip_one_complete_type (const DBusString *type_str, int *type_pos) { _dbus_type_signature_next (_dbus_string_get_const_data (type_str), type_pos); } /** * Skips to the next "complete" type inside a type signature. * The signature is read starting at type_pos, and the next * type position is stored in the same variable. * * @param type_str a type signature (must be valid) * @param type_pos an integer position in the type signature (in and out) */ void _dbus_type_signature_next (const char *type_str, int *type_pos) { const unsigned char *p; const unsigned char *start; _dbus_assert (type_str != NULL); _dbus_assert (type_pos != NULL); start = type_str; p = start + *type_pos; _dbus_assert (*p != DBUS_STRUCT_END_CHAR); _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); while (*p == DBUS_TYPE_ARRAY) ++p; _dbus_assert (*p != DBUS_STRUCT_END_CHAR); _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); if (*p == DBUS_STRUCT_BEGIN_CHAR) { int depth; depth = 1; while (TRUE) { _dbus_assert (*p != DBUS_TYPE_INVALID); ++p; _dbus_assert (*p != DBUS_TYPE_INVALID); if (*p == DBUS_STRUCT_BEGIN_CHAR) depth += 1; else if (*p == DBUS_STRUCT_END_CHAR) { depth -= 1; if (depth == 0) { ++p; break; } } } } else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) { int depth; depth = 1; while (TRUE) { _dbus_assert (*p != DBUS_TYPE_INVALID); ++p; _dbus_assert (*p != DBUS_TYPE_INVALID); if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) depth += 1; else if (*p == DBUS_DICT_ENTRY_END_CHAR) { depth -= 1; if (depth == 0) { ++p; break; } } } } else { ++p; } *type_pos = (int) (p - start); } static int find_len_of_complete_type (const DBusString *type_str, int type_pos) { int end; end = type_pos; skip_one_complete_type (type_str, &end); return end - type_pos; } static void base_reader_next (DBusTypeReader *reader, int current_type) { switch (current_type) { case DBUS_TYPE_DICT_ENTRY: case DBUS_TYPE_STRUCT: case DBUS_TYPE_VARIANT: /* Scan forward over the entire container contents */ { DBusTypeReader sub; if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT) ; else { /* Recurse into the struct or variant */ _dbus_type_reader_recurse (reader, &sub); /* Skip everything in this subreader */ while (_dbus_type_reader_next (&sub)) { /* nothing */; } } if (!reader->klass->types_only) reader->value_pos = sub.value_pos; /* Now we are at the end of this container; for variants, the * subreader's type_pos is totally inapplicable (it's in the * value string) but we know that we increment by one past the * DBUS_TYPE_VARIANT */ if (current_type == DBUS_TYPE_VARIANT) reader->type_pos += 1; else reader->type_pos = sub.type_pos; } break; case DBUS_TYPE_ARRAY: { if (!reader->klass->types_only) _dbus_marshal_skip_array (reader->value_str, _dbus_first_type_in_signature (reader->type_str, reader->type_pos + 1), reader->byte_order, &reader->value_pos); skip_one_complete_type (reader->type_str, &reader->type_pos); } break; default: if (!reader->klass->types_only) _dbus_marshal_skip_basic (reader->value_str, current_type, reader->byte_order, &reader->value_pos); reader->type_pos += 1; break; } } static void struct_reader_next (DBusTypeReader *reader, int current_type) { int t; base_reader_next (reader, current_type); /* for STRUCT containers we return FALSE at the end of the struct, * for INVALID we return FALSE at the end of the signature. * In both cases we arrange for get_current_type() to return INVALID * which is defined to happen iff we're at the end (no more next()) */ t = _dbus_string_get_byte (reader->type_str, reader->type_pos); if (t == DBUS_STRUCT_END_CHAR) { reader->type_pos += 1; reader->finished = TRUE; } } static void dict_entry_reader_next (DBusTypeReader *reader, int current_type) { int t; base_reader_next (reader, current_type); /* for STRUCT containers we return FALSE at the end of the struct, * for INVALID we return FALSE at the end of the signature. * In both cases we arrange for get_current_type() to return INVALID * which is defined to happen iff we're at the end (no more next()) */ t = _dbus_string_get_byte (reader->type_str, reader->type_pos); if (t == DBUS_DICT_ENTRY_END_CHAR) { reader->type_pos += 1; reader->finished = TRUE; } } static void array_types_only_reader_next (DBusTypeReader *reader, int current_type) { /* We have one "element" to be iterated over * in each array, which is its element type. * So the finished flag indicates whether we've * iterated over it yet or not. */ reader->finished = TRUE; } static void array_reader_next (DBusTypeReader *reader, int current_type) { /* Skip one array element */ int end_pos; end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", reader, reader->u.array.start_pos, end_pos, reader->value_pos, _dbus_type_to_string (current_type)); #endif _dbus_assert (reader->value_pos < end_pos); _dbus_assert (reader->value_pos >= reader->u.array.start_pos); switch (_dbus_first_type_in_signature (reader->type_str, reader->type_pos)) { case DBUS_TYPE_DICT_ENTRY: case DBUS_TYPE_STRUCT: case DBUS_TYPE_VARIANT: { DBusTypeReader sub; /* Recurse into the struct or variant */ _dbus_type_reader_recurse (reader, &sub); /* Skip everything in this element */ while (_dbus_type_reader_next (&sub)) { /* nothing */; } /* Now we are at the end of this element */ reader->value_pos = sub.value_pos; } break; case DBUS_TYPE_ARRAY: { _dbus_marshal_skip_array (reader->value_str, _dbus_first_type_in_signature (reader->type_str, reader->type_pos + 1), reader->byte_order, &reader->value_pos); } break; default: { _dbus_marshal_skip_basic (reader->value_str, current_type, reader->byte_order, &reader->value_pos); } break; } #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", reader, reader->u.array.start_pos, end_pos, reader->value_pos, _dbus_type_to_string (current_type)); #endif _dbus_assert (reader->value_pos <= end_pos); if (reader->value_pos == end_pos) { skip_one_complete_type (reader->type_str, &reader->type_pos); } } static const DBusTypeReaderClass body_reader_class = { "body", 0, FALSE, NULL, /* body is always toplevel, so doesn't get recursed into */ NULL, base_reader_next }; static const DBusTypeReaderClass body_types_only_reader_class = { "body types", 1, TRUE, NULL, /* body is always toplevel, so doesn't get recursed into */ NULL, base_reader_next }; static const DBusTypeReaderClass struct_reader_class = { "struct", 2, FALSE, struct_or_dict_entry_reader_recurse, NULL, struct_reader_next }; static const DBusTypeReaderClass struct_types_only_reader_class = { "struct types", 3, TRUE, struct_or_dict_entry_types_only_reader_recurse, NULL, struct_reader_next }; static const DBusTypeReaderClass dict_entry_reader_class = { "dict_entry", 4, FALSE, struct_or_dict_entry_reader_recurse, NULL, dict_entry_reader_next }; static const DBusTypeReaderClass dict_entry_types_only_reader_class = { "dict_entry types", 5, TRUE, struct_or_dict_entry_types_only_reader_recurse, NULL, dict_entry_reader_next }; static const DBusTypeReaderClass array_reader_class = { "array", 6, FALSE, array_reader_recurse, array_reader_check_finished, array_reader_next }; static const DBusTypeReaderClass array_types_only_reader_class = { "array types", 7, TRUE, array_types_only_reader_recurse, NULL, array_types_only_reader_next }; static const DBusTypeReaderClass variant_reader_class = { "variant", 8, FALSE, variant_reader_recurse, NULL, base_reader_next }; #ifndef DBUS_DISABLE_ASSERT static const DBusTypeReaderClass * const all_reader_classes[] = { &body_reader_class, &body_types_only_reader_class, &struct_reader_class, &struct_types_only_reader_class, &dict_entry_reader_class, &dict_entry_types_only_reader_class, &array_reader_class, &array_types_only_reader_class, &variant_reader_class }; #endif /** * Initializes a type reader. * * @param reader the reader * @param byte_order the byte order of the block to read * @param type_str the signature of the block to read * @param type_pos location of signature * @param value_str the string containing values block * @param value_pos start of values block */ void _dbus_type_reader_init (DBusTypeReader *reader, int byte_order, const DBusString *type_str, int type_pos, const DBusString *value_str, int value_pos) { reader_init (reader, byte_order, type_str, type_pos, value_str, value_pos); reader->klass = &body_reader_class; #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); #endif } /** * Like _dbus_type_reader_init() but the iteration is over the * signature, not over values. * * @param reader the reader * @param type_str the signature string * @param type_pos location in the signature string */ void _dbus_type_reader_init_types_only (DBusTypeReader *reader, const DBusString *type_str, int type_pos) { reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */, type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */); reader->klass = &body_types_only_reader_class; #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n", reader, reader->type_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); #endif } /** * Gets the type of the value the reader is currently pointing to; * or for a types-only reader gets the type it's currently pointing to. * If the reader is at the end of a block or end of a container such * as an array, returns #DBUS_TYPE_INVALID. * * @param reader the reader */ int _dbus_type_reader_get_current_type (const DBusTypeReader *reader) { int t; if (reader->finished || (reader->klass->check_finished && (* reader->klass->check_finished) (reader))) t = DBUS_TYPE_INVALID; else t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos); _dbus_assert (t != DBUS_STRUCT_END_CHAR); _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR); _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR); _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR); #if 0 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n", reader, reader->type_pos, _dbus_type_to_string (t)); #endif return t; } /** * Gets the type of an element of the array the reader is currently * pointing to. It's an error to call this if * _dbus_type_reader_get_current_type() doesn't return #DBUS_TYPE_ARRAY * for this reader. * * @param reader the reader */ int _dbus_type_reader_get_element_type (const DBusTypeReader *reader) { int element_type; _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY); element_type = _dbus_first_type_in_signature (reader->type_str, reader->type_pos + 1); return element_type; } /** * Gets the current position in the value block * @param reader the reader */ int _dbus_type_reader_get_value_pos (const DBusTypeReader *reader) { return reader->value_pos; } /** * Get the address of the marshaled value in the data being read. The * address may not be aligned; you have to align it to the type of the * value you want to read. Most of the demarshal routines do this for * you. * * @param reader the reader * @param value_location the address of the marshaled value */ void _dbus_type_reader_read_raw (const DBusTypeReader *reader, const unsigned char **value_location) { _dbus_assert (!reader->klass->types_only); *value_location = _dbus_string_get_const_data_len (reader->value_str, reader->value_pos, 0); } /** * Reads a basic-typed value, as with _dbus_marshal_read_basic(). * * @param reader the reader * @param value the address of the value */ void _dbus_type_reader_read_basic (const DBusTypeReader *reader, void *value) { int t; _dbus_assert (!reader->klass->types_only); t = _dbus_type_reader_get_current_type (reader); _dbus_marshal_read_basic (reader->value_str, reader->value_pos, t, value, reader->byte_order, NULL); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); #endif } /** * Returns the number of bytes in the array. * * @param reader the reader to read from * @returns the number of bytes in the array */ int _dbus_type_reader_get_array_length (const DBusTypeReader *reader) { _dbus_assert (!reader->klass->types_only); _dbus_assert (reader->klass == &array_reader_class); return array_reader_get_array_len (reader); } /** * Reads a block of fixed-length basic values, from the current point * in an array to the end of the array. Does not work for arrays of * string or container types. * * This function returns the array in-place; it does not make a copy, * and it does not swap the bytes. * * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back * and the "value" argument should be a "const double**" and so on. * * @param reader the reader to read from * @param value place to return the array values * @param n_elements place to return number of array elements */ void _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, void *value, int *n_elements) { int element_type; int end_pos; int remaining_len; int alignment; int total_len; _dbus_assert (!reader->klass->types_only); _dbus_assert (reader->klass == &array_reader_class); element_type = _dbus_first_type_in_signature (reader->type_str, reader->type_pos); _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */ _dbus_assert (dbus_type_is_fixed (element_type)); alignment = _dbus_type_get_alignment (element_type); _dbus_assert (reader->value_pos >= reader->u.array.start_pos); total_len = array_reader_get_array_len (reader); end_pos = reader->u.array.start_pos + total_len; remaining_len = end_pos - reader->value_pos; #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n", end_pos, total_len, remaining_len, reader->value_pos); #endif _dbus_assert (remaining_len <= total_len); if (remaining_len == 0) *(const DBusBasicValue**) value = NULL; else *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (reader->value_str, reader->value_pos, remaining_len); *n_elements = remaining_len / alignment; _dbus_assert ((remaining_len % alignment) == 0); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); #endif } /** * Initialize a new reader pointing to the first type and * corresponding value that's a child of the current container. It's * an error to call this if the current type is a non-container. * * Note that DBusTypeReader traverses values, not types. So if you * have an empty array of array of int, you can't recurse into it. You * can only recurse into each element. * * @param reader the reader * @param sub a reader to init pointing to the first child */ void _dbus_type_reader_recurse (DBusTypeReader *reader, DBusTypeReader *sub) { const DBusTypeReaderClass *klass; int t; t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos); switch (t) { case DBUS_TYPE_STRUCT: if (reader->klass->types_only) klass = &struct_types_only_reader_class; else klass = &struct_reader_class; break; case DBUS_TYPE_DICT_ENTRY: if (reader->klass->types_only) klass = &dict_entry_types_only_reader_class; else klass = &dict_entry_reader_class; break; case DBUS_TYPE_ARRAY: if (reader->klass->types_only) klass = &array_types_only_reader_class; else klass = &array_reader_class; break; case DBUS_TYPE_VARIANT: if (reader->klass->types_only) _dbus_assert_not_reached ("can't recurse into variant typecode"); else klass = &variant_reader_class; break; default: _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t)); #ifndef DBUS_DISABLE_CHECKS if (t == DBUS_TYPE_INVALID) _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n"); #endif /* DBUS_DISABLE_CHECKS */ _dbus_assert_not_reached ("don't yet handle recursing into this type"); } _dbus_assert (klass == all_reader_classes[klass->id]); (* klass->recurse) (sub, reader); sub->klass = klass; #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n", sub, sub->type_pos, sub->value_pos, _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0)); #endif } /** * Skip to the next value on this "level". e.g. the next field in a * struct, the next value in an array. Returns FALSE at the end of the * current container. * * @param reader the reader * @returns FALSE if nothing more to read at or below this level */ dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader) { int t; t = _dbus_type_reader_get_current_type (reader); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), _dbus_type_to_string (t)); #endif if (t == DBUS_TYPE_INVALID) return FALSE; (* reader->klass->next) (reader, t); #if RECURSIVE_MARSHAL_READ_TRACE _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), _dbus_type_to_string (_dbus_type_reader_get_current_type (reader))); #endif return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID; } /** * Check whether there's another value on this "level". e.g. the next * field in a struct, the next value in an array. Returns FALSE at the * end of the current container. * * You probably don't want to use this; it makes for an awkward for/while * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)" * * @param reader the reader * @returns FALSE if nothing more to read at or below this level */ dbus_bool_t _dbus_type_reader_has_next (const DBusTypeReader *reader) { /* Not efficient but works for now. */ DBusTypeReader copy; copy = *reader; return _dbus_type_reader_next (©); } /** * Gets the string and range of said string containing the signature * of the current value. Essentially a more complete version of * _dbus_type_reader_get_current_type() (returns the full type * rather than only the outside of the onion). * * Note though that the first byte in a struct signature is * #DBUS_STRUCT_BEGIN_CHAR while the current type will be * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the * signature is always the same as the current type. Another * difference is that this function will still return a signature when * inside an empty array; say you recurse into empty array of int32, * the signature is "i" but the current type will always be * #DBUS_TYPE_INVALID since there are no elements to be currently * pointing to. * * @param reader the reader * @param str_p place to return the string with the type in it * @param start_p place to return start of the type * @param len_p place to return the length of the type */ void _dbus_type_reader_get_signature (const DBusTypeReader *reader, const DBusString **str_p, int *start_p, int *len_p) { *str_p = reader->type_str; *start_p = reader->type_pos; *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos); } typedef struct { DBusString replacement; /**< Marshaled value including alignment padding */ int padding; /**< How much of the replacement block is padding */ } ReplacementBlock; static dbus_bool_t replacement_block_init (ReplacementBlock *block, DBusTypeReader *reader) { if (!_dbus_string_init (&block->replacement)) return FALSE; /* % 8 is the padding to have the same align properties in * our replacement string as we do at the position being replaced */ block->padding = reader->value_pos % 8; if (!_dbus_string_lengthen (&block->replacement, block->padding)) goto oom; return TRUE; oom: _dbus_string_free (&block->replacement); return FALSE; } static dbus_bool_t replacement_block_replace (ReplacementBlock *block, DBusTypeReader *reader, const DBusTypeReader *realign_root) { DBusTypeWriter writer; DBusTypeReader realign_reader; DBusList *fixups; int orig_len; _dbus_assert (realign_root != NULL); orig_len = _dbus_string_get_length (&block->replacement); realign_reader = *realign_root; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n", &writer, _dbus_string_get_length (&block->replacement)); #endif _dbus_type_writer_init_values_only (&writer, realign_reader.byte_order, realign_reader.type_str, realign_reader.type_pos, &block->replacement, _dbus_string_get_length (&block->replacement)); _dbus_assert (realign_reader.value_pos <= reader->value_pos); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n", realign_reader.value_pos, &writer, reader->value_pos); #endif fixups = NULL; if (!_dbus_type_writer_write_reader_partial (&writer, &realign_reader, reader, block->padding, _dbus_string_get_length (&block->replacement) - block->padding, &fixups)) goto oom; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding, _dbus_string_get_length (&block->replacement) - block->padding); _dbus_verbose_bytes_of_string (&block->replacement, block->padding, _dbus_string_get_length (&block->replacement) - block->padding); _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n", reader->value_pos, reader->value_pos % 8, realign_reader.value_pos - reader->value_pos, realign_reader.value_pos); _dbus_verbose_bytes_of_string (reader->value_str, reader->value_pos, realign_reader.value_pos - reader->value_pos); #endif /* Move the replacement into position * (realign_reader should now be at the end of the block to be replaced) */ if (!_dbus_string_replace_len (&block->replacement, block->padding, _dbus_string_get_length (&block->replacement) - block->padding, (DBusString*) reader->value_str, reader->value_pos, realign_reader.value_pos - reader->value_pos)) goto oom; /* Process our fixups now that we can't have an OOM error */ apply_and_free_fixups (&fixups, reader); return TRUE; oom: _dbus_string_set_length (&block->replacement, orig_len); free_fixups (&fixups); return FALSE; } static void replacement_block_free (ReplacementBlock *block) { _dbus_string_free (&block->replacement); } /* In the variable-length case, we have to fix alignment after we insert. * The strategy is as follows: * * - pad a new string to have the same alignment as the * start of the current basic value * - write the new basic value * - copy from the original reader to the new string, * which will fix the alignment of types following * the new value * - this copy has to start at realign_root, * but not really write anything until it * passes the value being set * - as an optimization, we can stop copying * when the source and dest values are both * on an 8-boundary, since we know all following * padding and alignment will be identical * - copy the new string back to the original * string, replacing the relevant part of the * original string * - now any arrays in the original string that * contained the replaced string may have the * wrong length; so we have to fix that */ static dbus_bool_t reader_set_basic_variable_length (DBusTypeReader *reader, int current_type, const void *value, const DBusTypeReader *realign_root) { dbus_bool_t retval; ReplacementBlock block; DBusTypeWriter writer; _dbus_assert (realign_root != NULL); retval = FALSE; if (!replacement_block_init (&block, reader)) return FALSE; /* Write the new basic value */ #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n", &writer, _dbus_string_get_length (&block.replacement)); #endif _dbus_type_writer_init_values_only (&writer, reader->byte_order, reader->type_str, reader->type_pos, &block.replacement, _dbus_string_get_length (&block.replacement)); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer); #endif if (!_dbus_type_writer_write_basic (&writer, current_type, value)) goto out; if (!replacement_block_replace (&block, reader, realign_root)) goto out; retval = TRUE; out: replacement_block_free (&block); return retval; } static void reader_set_basic_fixed_length (DBusTypeReader *reader, int current_type, const void *value) { _dbus_marshal_set_basic ((DBusString*) reader->value_str, reader->value_pos, current_type, value, reader->byte_order, NULL, NULL); } /** * Sets a new value for the basic type value pointed to by the reader, * leaving the reader valid to continue reading. Any other readers * will be invalidated if you set a variable-length type such as a * string. * * The provided realign_root is the reader to start from when * realigning the data that follows the newly-set value. The reader * parameter must point to a value below the realign_root parameter. * If the type being set is fixed-length, then realign_root may be * #NULL. Only values reachable from realign_root will be realigned, * so if your string contains other values you will need to deal with * those somehow yourself. It is OK if realign_root is the same * reader as the reader parameter, though if you aren't setting the * root it may not be such a good idea. * * @todo DBusTypeReader currently takes "const" versions of the type * and value strings, and this function modifies those strings by * casting away the const, which is of course bad if we want to get * picky. (To be truly clean you'd have an object which contained the * type and value strings and set_basic would be a method on that * object... this would also make DBusTypeReader the same thing as * DBusTypeMark. But since DBusMessage is effectively that object for * D-Bus it doesn't seem worth creating some random object.) * * @todo optimize this by only rewriting until the old and new values * are at the same alignment. Frequently this should result in only * replacing the value that's immediately at hand. * * @param reader reader indicating where to set a new value * @param value address of the value to set * @param realign_root realign from here * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_type_reader_set_basic (DBusTypeReader *reader, const void *value, const DBusTypeReader *realign_root) { int current_type; _dbus_assert (!reader->klass->types_only); _dbus_assert (reader->value_str == realign_root->value_str); _dbus_assert (reader->value_pos >= realign_root->value_pos); current_type = _dbus_type_reader_get_current_type (reader); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n", reader, reader->type_pos, reader->value_pos, _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), realign_root, realign_root ? realign_root->value_pos : -1, _dbus_type_to_string (current_type)); _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos, _dbus_string_get_length (realign_root->value_str) - realign_root->value_pos); #endif _dbus_assert (dbus_type_is_basic (current_type)); if (dbus_type_is_fixed (current_type)) { reader_set_basic_fixed_length (reader, current_type, value); return TRUE; } else { _dbus_assert (realign_root != NULL); return reader_set_basic_variable_length (reader, current_type, value, realign_root); } } /** * Recursively deletes any value pointed to by the reader, leaving the * reader valid to continue reading. Any other readers will be * invalidated. * * The provided realign_root is the reader to start from when * realigning the data that follows the newly-set value. * See _dbus_type_reader_set_basic() for more details on the * realign_root paramter. * * @todo for now this does not delete the typecodes associated with * the value, so this function should only be used for array elements. * * @param reader reader indicating where to delete a value * @param realign_root realign from here * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_type_reader_delete (DBusTypeReader *reader, const DBusTypeReader *realign_root) { dbus_bool_t retval; ReplacementBlock block; _dbus_assert (realign_root != NULL); _dbus_assert (reader->klass == &array_reader_class); retval = FALSE; if (!replacement_block_init (&block, reader)) return FALSE; if (!replacement_block_replace (&block, reader, realign_root)) goto out; retval = TRUE; out: replacement_block_free (&block); return retval; } /* * Compares two readers, which must be iterating over the same value data. * Returns #TRUE if the first parameter is further along than the second parameter. * * @param lhs left-hand-side (first) parameter * @param rhs left-hand-side (first) parameter * @returns whether lhs is greater than rhs */ static dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs, const DBusTypeReader *rhs) { _dbus_assert (lhs->value_str == rhs->value_str); return lhs->value_pos > rhs->value_pos; } /* * * * DBusTypeWriter * * * */ /** * Initialize a write iterator, which is used to write out values in * serialized D-Bus format. * * The type_pos passed in is expected to be inside an already-valid, * though potentially empty, type signature. This means that the byte * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some * other valid type. #DBusTypeWriter won't enforce that the signature * is already valid (you can append the nul byte at the end if you * like), but just be aware that you need the nul byte eventually and * #DBusTypeWriter isn't going to write it for you. * * @param writer the writer to init * @param byte_order the byte order to marshal into * @param type_str the string to write typecodes into * @param type_pos where to insert typecodes * @param value_str the string to write values into * @param value_pos where to insert values * */ void _dbus_type_writer_init (DBusTypeWriter *writer, int byte_order, DBusString *type_str, int type_pos, DBusString *value_str, int value_pos) { writer->byte_order = byte_order; writer->type_str = type_str; writer->type_pos = type_pos; writer->value_str = value_str; writer->value_pos = value_pos; writer->container_type = DBUS_TYPE_INVALID; writer->type_pos_is_expectation = FALSE; writer->enabled = TRUE; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("writer %p init remaining sig '%s'\n", writer, writer->type_str ? _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : "unknown"); #endif } /** * Initialize a write iterator, with the signature to be provided * later. * * @param writer the writer to init * @param byte_order the byte order to marshal into * @param value_str the string to write values into * @param value_pos where to insert values * */ void _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, int byte_order, DBusString *value_str, int value_pos) { _dbus_type_writer_init (writer, byte_order, NULL, 0, value_str, value_pos); } /** * Adds type string to the writer, if it had none. * * @param writer the writer to init * @param type_str type string to add * @param type_pos type position * */ void _dbus_type_writer_add_types (DBusTypeWriter *writer, DBusString *type_str, int type_pos) { if (writer->type_str == NULL) /* keeps us from using this as setter */ { writer->type_str = type_str; writer->type_pos = type_pos; } } /** * Removes type string from the writer. * * @param writer the writer to remove from */ void _dbus_type_writer_remove_types (DBusTypeWriter *writer) { writer->type_str = NULL; writer->type_pos = -1; } /** * Like _dbus_type_writer_init(), except the type string * passed in should correspond to an existing signature that * matches what you're going to write out. The writer will * check what you write vs. this existing signature. * * @param writer the writer to init * @param byte_order the byte order to marshal into * @param type_str the string with signature * @param type_pos start of signature * @param value_str the string to write values into * @param value_pos where to insert values * */ void _dbus_type_writer_init_values_only (DBusTypeWriter *writer, int byte_order, const DBusString *type_str, int type_pos, DBusString *value_str, int value_pos) { _dbus_type_writer_init (writer, byte_order, (DBusString*)type_str, type_pos, value_str, value_pos); writer->type_pos_is_expectation = TRUE; } static dbus_bool_t _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer, int type, const void *value) { if (writer->enabled) return _dbus_marshal_write_basic (writer->value_str, writer->value_pos, type, value, writer->byte_order, &writer->value_pos); else return TRUE; } /* If our parent is an array, things are a little bit complicated. * * The parent must have a complete element type, such as * "i" or "aai" or "(ii)" or "a(ii)". There can't be * unclosed parens, or an "a" with no following type. * * To recurse, the only allowed operation is to recurse into the * first type in the element type. So for "i" you can't recurse, for * "ai" you can recurse into the array, for "(ii)" you can recurse * into the struct. * * If you recurse into the array for "ai", then you must specify * "i" for the element type of the array you recurse into. * * While inside an array at any level, we need to avoid writing to * type_str, since the type only appears once for the whole array, * it does not appear for each array element. * * While inside an array type_pos points to the expected next * typecode, rather than the next place we could write a typecode. */ static void writer_recurse_init_and_check (DBusTypeWriter *writer, int container_type, DBusTypeWriter *sub) { _dbus_type_writer_init (sub, writer->byte_order, writer->type_str, writer->type_pos, writer->value_str, writer->value_pos); sub->container_type = container_type; if (writer->type_pos_is_expectation || (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT)) sub->type_pos_is_expectation = TRUE; else sub->type_pos_is_expectation = FALSE; sub->enabled = writer->enabled; #ifndef DBUS_DISABLE_CHECKS if (writer->type_pos_is_expectation && writer->type_str) { int expected; expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos); if (expected != sub->container_type) { if (expected != DBUS_TYPE_INVALID) _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n" "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", _dbus_type_to_string (sub->container_type), _dbus_type_to_string (expected), _dbus_string_get_const_data (writer->type_str), writer->type_pos); else _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n" "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", _dbus_type_to_string (sub->container_type), _dbus_string_get_const_data (writer->type_str), writer->type_pos); _dbus_assert_not_reached ("bad array element or variant content written"); } } #endif /* DBUS_DISABLE_CHECKS */ #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n", writer, _dbus_type_to_string (writer->container_type), writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, writer->type_str ? _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : "unknown", writer->enabled); _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", sub, _dbus_type_to_string (sub->container_type), sub->type_pos, sub->value_pos, sub->type_pos_is_expectation, sub->enabled); #endif } static dbus_bool_t write_or_verify_typecode (DBusTypeWriter *writer, int typecode) { /* A subwriter inside an array or variant will have type_pos * pointing to the expected typecode; a writer not inside an array * or variant has type_pos pointing to the next place to insert a * typecode. */ #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n", writer, writer->type_pos, writer->type_str ? _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : "unknown", writer->enabled); #endif if (writer->type_str == NULL) return TRUE; if (writer->type_pos_is_expectation) { #ifndef DBUS_DISABLE_CHECKS { int expected; expected = _dbus_string_get_byte (writer->type_str, writer->type_pos); if (expected != typecode) { if (expected != DBUS_TYPE_INVALID) _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n" "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", _dbus_type_to_string (expected), _dbus_type_to_string (typecode), _dbus_string_get_const_data (writer->type_str), writer->type_pos); else _dbus_warn_check_failed ("Array or variant type wasn't expecting any more values to be written into it, but a value %s was written.\n" "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", _dbus_type_to_string (typecode), _dbus_string_get_const_data (writer->type_str), writer->type_pos); _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant"); } } #endif /* DBUS_DISABLE_CHECKS */ /* if immediately inside an array we'd always be appending an element, * so the expected type doesn't change; if inside a struct or something * below an array, we need to move through said struct or something. */ if (writer->container_type != DBUS_TYPE_ARRAY) writer->type_pos += 1; } else { if (!_dbus_string_insert_byte (writer->type_str, writer->type_pos, typecode)) return FALSE; writer->type_pos += 1; } #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n", writer, writer->type_pos, _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0)); #endif return TRUE; } static dbus_bool_t writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer, int begin_char, const DBusString *contained_type, int contained_type_start, int contained_type_len, DBusTypeWriter *sub) { /* FIXME right now contained_type is ignored; we could probably * almost trivially fix the code so if it's present we * write it out and then set type_pos_is_expectation */ /* Ensure that we'll be able to add alignment padding and the typecode */ if (writer->enabled) { if (!_dbus_string_alloc_space (sub->value_str, 8)) return FALSE; } if (!write_or_verify_typecode (sub, begin_char)) _dbus_assert_not_reached ("failed to insert struct typecode after prealloc"); if (writer->enabled) { if (!_dbus_string_insert_bytes (sub->value_str, sub->value_pos, _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos, '\0')) _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct"); sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); } return TRUE; } static dbus_bool_t writer_recurse_array (DBusTypeWriter *writer, const DBusString *contained_type, int contained_type_start, int contained_type_len, DBusTypeWriter *sub, dbus_bool_t is_array_append) { dbus_uint32_t value = 0; int alignment; int aligned; #ifndef DBUS_DISABLE_CHECKS if (writer->container_type == DBUS_TYPE_ARRAY && writer->type_str) { if (!_dbus_string_equal_substring (contained_type, contained_type_start, contained_type_len, writer->type_str, writer->u.array.element_type_pos + 1)) { _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n", _dbus_string_get_const_data_len (contained_type, contained_type_start, contained_type_len)); _dbus_assert_not_reached ("incompatible type for child array"); } } #endif /* DBUS_DISABLE_CHECKS */ if (writer->enabled && !is_array_append) { /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding * before array values */ if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4)) return FALSE; } if (writer->type_str != NULL) { sub->type_pos += 1; /* move to point to the element type, since type_pos * should be the expected type for further writes */ sub->u.array.element_type_pos = sub->type_pos; } if (!writer->type_pos_is_expectation) { /* sub is a toplevel/outermost array so we need to write the type data */ /* alloc space for array typecode, element signature */ if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len)) return FALSE; if (!_dbus_string_insert_byte (writer->type_str, writer->type_pos, DBUS_TYPE_ARRAY)) _dbus_assert_not_reached ("failed to insert array typecode after prealloc"); if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len, sub->type_str, sub->u.array.element_type_pos)) _dbus_assert_not_reached ("should not have failed to insert array element typecodes"); } if (writer->type_str != NULL) { /* If the parent is an array, we hold type_pos pointing at the array element type; * otherwise advance it to reflect the array value we just recursed into */ if (writer->container_type != DBUS_TYPE_ARRAY) writer->type_pos += 1 + contained_type_len; else _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */ } if (writer->enabled) { /* Write (or jump over, if is_array_append) the length */ sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); if (is_array_append) { sub->value_pos += 4; } else { if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32, &value)) _dbus_assert_not_reached ("should not have failed to insert array len"); } _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4); /* Write alignment padding for array elements * Note that we write the padding *even for empty arrays* * to avoid wonky special cases */ alignment = element_type_get_alignment (contained_type, contained_type_start); aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); if (aligned != sub->value_pos) { if (!is_array_append) { if (!_dbus_string_insert_bytes (sub->value_str, sub->value_pos, aligned - sub->value_pos, '\0')) _dbus_assert_not_reached ("should not have failed to insert alignment padding"); } sub->value_pos = aligned; } sub->u.array.start_pos = sub->value_pos; if (is_array_append) { dbus_uint32_t len; _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) == (unsigned) sub->u.array.len_pos); len = _dbus_unpack_uint32 (sub->byte_order, _dbus_string_get_const_data_len (sub->value_str, sub->u.array.len_pos, 4)); sub->value_pos += len; } } else { /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */ sub->u.array.len_pos = -1; sub->u.array.start_pos = sub->value_pos; } _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos); _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub, sub->type_str ? _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) : "unknown", sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos); #endif return TRUE; } /* Variant value will normally have: * 1 byte signature length not including nul * signature typecodes (nul terminated) * padding to alignment of contained type * body according to signature * * The signature string can only have a single type * in it but that type may be complex/recursive. * * So a typical variant type with the integer 3 will have these * octets: * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3 * * The main world of hurt for writing out a variant is that the type * string is the same string as the value string. Which means * inserting to the type string will move the value_pos; and it means * that inserting to the type string could break type alignment. */ static dbus_bool_t writer_recurse_variant (DBusTypeWriter *writer, const DBusString *contained_type, int contained_type_start, int contained_type_len, DBusTypeWriter *sub) { int contained_alignment; if (writer->enabled) { /* Allocate space for the worst case, which is 1 byte sig * length, nul byte at end of sig, and 7 bytes padding to * 8-boundary. */ if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9)) return FALSE; } /* write VARIANT typecode to the parent's type string */ if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT)) return FALSE; /* If not enabled, mark that we have no type_str anymore ... */ if (!writer->enabled) { sub->type_str = NULL; sub->type_pos = -1; return TRUE; } /* If we're enabled then continue ... */ if (!_dbus_string_insert_byte (sub->value_str, sub->value_pos, contained_type_len)) _dbus_assert_not_reached ("should not have failed to insert variant type sig len"); sub->value_pos += 1; /* Here we switch over to the expected type sig we're about to write */ sub->type_str = sub->value_str; sub->type_pos = sub->value_pos; if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len, sub->value_str, sub->value_pos)) _dbus_assert_not_reached ("should not have failed to insert variant type sig"); sub->value_pos += contained_type_len; if (!_dbus_string_insert_byte (sub->value_str, sub->value_pos, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("should not have failed to insert variant type nul termination"); sub->value_pos += 1; contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start)); if (!_dbus_string_insert_bytes (sub->value_str, sub->value_pos, _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos, '\0')) _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body"); sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); return TRUE; } static dbus_bool_t _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer, int container_type, const DBusString *contained_type, int contained_type_start, int contained_type_len, DBusTypeWriter *sub, dbus_bool_t is_array_append) { writer_recurse_init_and_check (writer, container_type, sub); switch (container_type) { case DBUS_TYPE_STRUCT: return writer_recurse_struct_or_dict_entry (writer, DBUS_STRUCT_BEGIN_CHAR, contained_type, contained_type_start, contained_type_len, sub); break; case DBUS_TYPE_DICT_ENTRY: return writer_recurse_struct_or_dict_entry (writer, DBUS_DICT_ENTRY_BEGIN_CHAR, contained_type, contained_type_start, contained_type_len, sub); break; case DBUS_TYPE_ARRAY: return writer_recurse_array (writer, contained_type, contained_type_start, contained_type_len, sub, is_array_append); break; case DBUS_TYPE_VARIANT: return writer_recurse_variant (writer, contained_type, contained_type_start, contained_type_len, sub); break; default: _dbus_assert_not_reached ("tried to recurse into type that doesn't support that"); return FALSE; break; } } /** * Opens a new container and writes out the initial information for that container. * * @param writer the writer * @param container_type the type of the container to open * @param contained_type the array element type or variant content type * @param contained_type_start position to look for the type * @param sub the new sub-writer to write container contents * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer, int container_type, const DBusString *contained_type, int contained_type_start, DBusTypeWriter *sub) { int contained_type_len; if (contained_type) contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); else contained_type_len = 0; return _dbus_type_writer_recurse_contained_len (writer, container_type, contained_type, contained_type_start, contained_type_len, sub, FALSE); } /** * Append to an existing array. Essentially, the writer will read an * existing length at the write location; jump over that length; and * write new fields. On unrecurse(), the existing length will be * updated. * * @param writer the writer * @param contained_type element type * @param contained_type_start position of element type * @param sub the subwriter to init * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_append_array (DBusTypeWriter *writer, const DBusString *contained_type, int contained_type_start, DBusTypeWriter *sub) { int contained_type_len; if (contained_type) contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); else contained_type_len = 0; return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY, contained_type, contained_type_start, contained_type_len, sub, TRUE); } static int writer_get_array_len (DBusTypeWriter *writer) { _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); return writer->value_pos - writer->u.array.start_pos; } /** * Closes a container created by _dbus_type_writer_recurse() * and writes any additional information to the values block. * * @param writer the writer * @param sub the sub-writer created by _dbus_type_writer_recurse() * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_unrecurse (DBusTypeWriter *writer, DBusTypeWriter *sub) { /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */ _dbus_assert (!writer->type_pos_is_expectation || (writer->type_pos_is_expectation && sub->type_pos_is_expectation)); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, _dbus_type_to_string (writer->container_type)); _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", sub, sub->type_pos, sub->value_pos, sub->type_pos_is_expectation, _dbus_type_to_string (sub->container_type)); #endif if (sub->container_type == DBUS_TYPE_STRUCT) { if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR)) return FALSE; } else if (sub->container_type == DBUS_TYPE_DICT_ENTRY) { if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR)) return FALSE; } else if (sub->container_type == DBUS_TYPE_ARRAY) { if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */ { dbus_uint32_t len; /* Set the array length */ len = writer_get_array_len (sub); _dbus_marshal_set_uint32 (sub->value_str, sub->u.array.len_pos, len, sub->byte_order); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" filled in sub array len to %u at len_pos %d\n", len, sub->u.array.len_pos); #endif } #if RECURSIVE_MARSHAL_WRITE_TRACE else { _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n"); } #endif } /* Now get type_pos right for the parent writer. Here are the cases: * * Cases !writer->type_pos_is_expectation: * (in these cases we want to update to the new insertion point) * * - if we recursed into a STRUCT then we didn't know in advance * what the types in the struct would be; so we have to fill in * that information now. * writer->type_pos = sub->type_pos * * - if we recursed into anything else, we knew the full array * type, or knew the single typecode marking VARIANT, so * writer->type_pos is already correct. * writer->type_pos should remain as-is * * - note that the parent is never an ARRAY or VARIANT, if it were * then type_pos_is_expectation would be TRUE. The parent * is thus known to be a toplevel or STRUCT. * * Cases where writer->type_pos_is_expectation: * (in these cases we want to update to next expected type to write) * * - we recursed from STRUCT into STRUCT and we didn't increment * type_pos in the parent just to stay consistent with the * !writer->type_pos_is_expectation case (though we could * special-case this in recurse_struct instead if we wanted) * writer->type_pos = sub->type_pos * * - we recursed from STRUCT into ARRAY or VARIANT and type_pos * for parent should have been incremented already * writer->type_pos should remain as-is * * - we recursed from ARRAY into a sub-element, so type_pos in the * parent is the element type and should remain the element type * for the benefit of the next child element * writer->type_pos should remain as-is * * - we recursed from VARIANT into its value, so type_pos in the * parent makes no difference since there's only one value * and we just finished writing it and won't use type_pos again * writer->type_pos should remain as-is * * * For all these, DICT_ENTRY is the same as STRUCT */ if (writer->type_str != NULL) { if ((sub->container_type == DBUS_TYPE_STRUCT || sub->container_type == DBUS_TYPE_DICT_ENTRY) && (writer->container_type == DBUS_TYPE_STRUCT || writer->container_type == DBUS_TYPE_DICT_ENTRY || writer->container_type == DBUS_TYPE_INVALID)) { /* Advance the parent to the next struct field */ writer->type_pos = sub->type_pos; } } writer->value_pos = sub->value_pos; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n", writer, writer->type_pos, writer->value_pos, writer->type_str ? _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : "unknown"); #endif return TRUE; } /** * Writes out a basic type. * * @param writer the writer * @param type the type to write * @param value the address of the value to write * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer, int type, const void *value) { dbus_bool_t retval; /* First ensure that our type realloc will succeed */ if (!writer->type_pos_is_expectation && writer->type_str != NULL) { if (!_dbus_string_alloc_space (writer->type_str, 1)) return FALSE; } retval = FALSE; if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value)) goto out; if (!write_or_verify_typecode (writer, type)) _dbus_assert_not_reached ("failed to write typecode after prealloc"); retval = TRUE; out: #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, writer->enabled); #endif return retval; } /** * Writes a block of fixed-length basic values, i.e. those that are * both dbus_type_is_fixed() and _dbus_type_is_basic(). The block * must be written inside an array. * * The value parameter should be the address of said array of values, * so e.g. if it's an array of double, pass in "const double**" * * @param writer the writer * @param element_type type of stuff in the array * @param value address of the array * @param n_elements number of elements in the array * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, int element_type, const void *value, int n_elements) { _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (writer->type_pos_is_expectation); _dbus_assert (n_elements >= 0); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n", writer, writer->type_pos, writer->value_pos, n_elements); #endif if (!write_or_verify_typecode (writer, element_type)) _dbus_assert_not_reached ("OOM should not happen if only verifying typecode"); if (writer->enabled) { if (!_dbus_marshal_write_fixed_multi (writer->value_str, writer->value_pos, element_type, value, n_elements, writer->byte_order, &writer->value_pos)) return FALSE; } #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose (" type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n", writer, writer->type_pos, writer->value_pos, n_elements); #endif return TRUE; } static void enable_if_after (DBusTypeWriter *writer, DBusTypeReader *reader, const DBusTypeReader *start_after) { if (start_after) { if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after)) { _dbus_type_writer_set_enabled (writer, TRUE); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n", writer, writer->value_pos, reader->value_pos, start_after->value_pos); #endif } _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) || (writer->enabled && _dbus_type_reader_greater_than (reader, start_after))); } } static dbus_bool_t append_fixup (DBusList **fixups, const DBusArrayLenFixup *fixup) { DBusArrayLenFixup *f; f = dbus_new (DBusArrayLenFixup, 1); if (f == NULL) return FALSE; *f = *fixup; if (!_dbus_list_append (fixups, f)) { dbus_free (f); return FALSE; } _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader); _dbus_assert (f->new_len == fixup->new_len); return TRUE; } /* This loop is trivial if you ignore all the start_after nonsense, * so if you're trying to figure it out, start by ignoring that */ static dbus_bool_t writer_write_reader_helper (DBusTypeWriter *writer, DBusTypeReader *reader, const DBusTypeReader *start_after, int start_after_new_pos, int start_after_new_len, DBusList **fixups, dbus_bool_t inside_start_after) { int current_type; while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) { if (dbus_type_is_container (current_type)) { DBusTypeReader subreader; DBusTypeWriter subwriter; const DBusString *sig_str; int sig_start; int sig_len; dbus_bool_t enabled_at_recurse; dbus_bool_t past_start_after; int reader_array_len_pos; int reader_array_start_pos; dbus_bool_t this_is_start_after; /* type_pos is checked since e.g. in a struct the struct * and its first field have the same value_pos. * type_str will differ in reader/start_after for variants * where type_str is inside the value_str */ if (!inside_start_after && start_after && reader->value_pos == start_after->value_pos && reader->type_str == start_after->type_str && reader->type_pos == start_after->type_pos) this_is_start_after = TRUE; else this_is_start_after = FALSE; _dbus_type_reader_recurse (reader, &subreader); if (current_type == DBUS_TYPE_ARRAY) { reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader); reader_array_start_pos = subreader.u.array.start_pos; } else { /* quiet gcc */ reader_array_len_pos = -1; reader_array_start_pos = -1; } _dbus_type_reader_get_signature (&subreader, &sig_str, &sig_start, &sig_len); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n", _dbus_type_to_string (current_type), reader->value_pos, subreader.value_pos, writer->value_pos, start_after ? start_after->value_pos : -1, _dbus_string_get_length (writer->value_str), inside_start_after, this_is_start_after); #endif if (!inside_start_after && !this_is_start_after) enable_if_after (writer, &subreader, start_after); enabled_at_recurse = writer->enabled; if (!_dbus_type_writer_recurse_contained_len (writer, current_type, sig_str, sig_start, sig_len, &subwriter, FALSE)) goto oom; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("recursed into subwriter at %d write target len %d\n", subwriter.value_pos, _dbus_string_get_length (subwriter.value_str)); #endif if (!writer_write_reader_helper (&subwriter, &subreader, start_after, start_after_new_pos, start_after_new_len, fixups, inside_start_after || this_is_start_after)) goto oom; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d write target len %d\n", _dbus_type_to_string (current_type), subreader.value_pos, writer->value_pos, subwriter.value_pos, _dbus_string_get_length (writer->value_str)); #endif if (!inside_start_after && !this_is_start_after) enable_if_after (writer, &subreader, start_after); past_start_after = writer->enabled; if (!_dbus_type_writer_unrecurse (writer, &subwriter)) goto oom; /* If we weren't enabled when we recursed, we didn't * write an array len; if we passed start_after * somewhere inside the array, then we need to generate * a fixup. */ if (start_after != NULL && !enabled_at_recurse && past_start_after && current_type == DBUS_TYPE_ARRAY && fixups != NULL) { DBusArrayLenFixup fixup; int bytes_written_after_start_after; int bytes_before_start_after; int old_len; /* this subwriter access is moderately unkosher since we * already unrecursed, but it works as long as unrecurse * doesn't break us on purpose */ bytes_written_after_start_after = writer_get_array_len (&subwriter); bytes_before_start_after = start_after->value_pos - reader_array_start_pos; fixup.len_pos_in_reader = reader_array_len_pos; fixup.new_len = bytes_before_start_after + start_after_new_len + bytes_written_after_start_after; _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) == (unsigned) fixup.len_pos_in_reader); old_len = _dbus_unpack_uint32 (reader->byte_order, _dbus_string_get_const_data_len (reader->value_str, fixup.len_pos_in_reader, 4)); if (old_len != fixup.new_len && !append_fixup (fixups, &fixup)) goto oom; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n", fixup.len_pos_in_reader, fixup.new_len, reader_array_start_pos, start_after->value_pos, bytes_before_start_after, start_after_new_len, bytes_written_after_start_after); #endif } } else { DBusBasicValue val; _dbus_assert (dbus_type_is_basic (current_type)); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("Reading basic value %s at %d\n", _dbus_type_to_string (current_type), reader->value_pos); #endif _dbus_type_reader_read_basic (reader, &val); #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n", _dbus_type_to_string (current_type), writer->value_pos, _dbus_string_get_length (writer->value_str), inside_start_after); #endif if (!inside_start_after) enable_if_after (writer, reader, start_after); if (!_dbus_type_writer_write_basic (writer, current_type, &val)) goto oom; #if RECURSIVE_MARSHAL_WRITE_TRACE _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n", _dbus_type_to_string (current_type), writer->value_pos, _dbus_string_get_length (writer->value_str)); #endif } _dbus_type_reader_next (reader); } return TRUE; oom: if (fixups) apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */ return FALSE; } /* * Iterate through all values in the given reader, writing a copy of * each value to the writer. The reader will be moved forward to its * end position. * * If a reader start_after is provided, it should be a reader for the * same data as the reader to be written. Only values occurring after * the value pointed to by start_after will be written to the writer. * * If start_after is provided, then the copy of the reader will be * partial. This means that array lengths will not have been copied. * The assumption is that you wrote a new version of the value at * start_after to the writer. You have to pass in the start position * and length of the new value. (If you are deleting the value * at start_after, pass in 0 for the length.) * * If the fixups parameter is non-#NULL, then any array length that * was read but not written due to start_after will be provided * as a #DBusArrayLenFixup. The fixup contains the position of the * array length in the source data, and the correct array length * assuming you combine the source data before start_after with * the written data at start_after and beyond. * * @param writer the writer to copy to * @param reader the reader to copy from * @param start_after #NULL or a reader showing where to start * @param start_after_new_pos the position of start_after equivalent in the target data * @param start_after_new_len the length of start_after equivalent in the target data * @param fixups list to append #DBusArrayLenFixup if the write was partial * @returns #FALSE if no memory */ static dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, DBusTypeReader *reader, const DBusTypeReader *start_after, int start_after_new_pos, int start_after_new_len, DBusList **fixups) { DBusTypeWriter orig; int orig_type_len; int orig_value_len; int new_bytes; int orig_enabled; orig = *writer; orig_type_len = _dbus_string_get_length (writer->type_str); orig_value_len = _dbus_string_get_length (writer->value_str); orig_enabled = writer->enabled; if (start_after) _dbus_type_writer_set_enabled (writer, FALSE); if (!writer_write_reader_helper (writer, reader, start_after, start_after_new_pos, start_after_new_len, fixups, FALSE)) goto oom; _dbus_type_writer_set_enabled (writer, orig_enabled); return TRUE; oom: if (!writer->type_pos_is_expectation) { new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len; _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes); } new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len; _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes); *writer = orig; return FALSE; } /** * Iterate through all values in the given reader, writing a copy of * each value to the writer. The reader will be moved forward to its * end position. * * @param writer the writer to copy to * @param reader the reader to copy from * @returns #FALSE if no memory */ dbus_bool_t _dbus_type_writer_write_reader (DBusTypeWriter *writer, DBusTypeReader *reader) { return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL); } /* * If disabled, a writer can still be iterated forward and recursed/unrecursed * but won't write any values. Types will still be written unless the * writer is a "values only" writer, because the writer needs access to * a valid signature to be able to iterate. * * @param writer the type writer * @param enabled #TRUE if values should be written */ static void _dbus_type_writer_set_enabled (DBusTypeWriter *writer, dbus_bool_t enabled) { writer->enabled = enabled != FALSE; } /** @} */ /* end of DBusMarshal group */ /* tests in dbus-marshal-recursive-util.c */ dbus-1.10.6/dbus/dbus-marshal-byteswap.h0000644000175000017500000000275312602773110020070 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-byteswap.h Swap a block of marshaled data * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MARSHAL_BYTESWAP_H #define DBUS_MARSHAL_BYTESWAP_H #include #include DBUS_PRIVATE_EXPORT void _dbus_marshal_byteswap (const DBusString *signature, int signature_start, int old_byte_order, int new_byte_order, DBusString *value_str, int value_pos); #endif /* DBUS_MARSHAL_BYTESWAP_H */ dbus-1.10.6/dbus/dbus-marshal-byteswap.c0000644000175000017500000001665712624705346020105 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-byteswap.c Swap a block of marshaled data * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-marshal-byteswap.h" #include "dbus-marshal-basic.h" #include "dbus-signature.h" /** * @addtogroup DBusMarshal * @{ */ static void byteswap_body_helper (DBusTypeReader *reader, dbus_bool_t walk_reader_to_end, int old_byte_order, int new_byte_order, unsigned char *p, unsigned char **new_p) { int current_type; while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) { switch (current_type) { case DBUS_TYPE_BYTE: ++p; break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: { p = _DBUS_ALIGN_ADDRESS (p, 2); *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p)); p += 2; } break; case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: { p = _DBUS_ALIGN_ADDRESS (p, 4); *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); p += 4; } break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: { p = _DBUS_ALIGN_ADDRESS (p, 8); *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p)); p += 8; } break; case DBUS_TYPE_ARRAY: case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: { dbus_uint32_t array_len; p = _DBUS_ALIGN_ADDRESS (p, 4); array_len = _dbus_unpack_uint32 (old_byte_order, p); *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); p += 4; if (current_type == DBUS_TYPE_ARRAY) { int elem_type; int alignment; elem_type = _dbus_type_reader_get_element_type (reader); alignment = _dbus_type_get_alignment (elem_type); _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH); p = _DBUS_ALIGN_ADDRESS (p, alignment); if (dbus_type_is_fixed (elem_type)) { if (alignment > 1) _dbus_swap_array (p, array_len / alignment, alignment); p += array_len; } else { DBusTypeReader sub; const unsigned char *array_end; array_end = p + array_len; _dbus_type_reader_recurse (reader, &sub); while (p < array_end) { byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); } } } else { _dbus_assert (current_type == DBUS_TYPE_STRING || current_type == DBUS_TYPE_OBJECT_PATH); p += (array_len + 1); /* + 1 for nul */ } } break; case DBUS_TYPE_SIGNATURE: { dbus_uint32_t sig_len; sig_len = *p; p += (sig_len + 2); /* +2 for len and nul */ } break; case DBUS_TYPE_VARIANT: { /* 1 byte sig len, sig typecodes, align to * contained-type-boundary, values. */ dbus_uint32_t sig_len; DBusString sig; DBusTypeReader sub; int contained_alignment; sig_len = *p; ++p; _dbus_string_init_const_len (&sig, p, sig_len); p += (sig_len + 1); /* 1 for nul */ contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0)); p = _DBUS_ALIGN_ADDRESS (p, contained_alignment); _dbus_type_reader_init_types_only (&sub, &sig, 0); byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); } break; case DBUS_TYPE_STRUCT: case DBUS_TYPE_DICT_ENTRY: { DBusTypeReader sub; p = _DBUS_ALIGN_ADDRESS (p, 8); _dbus_type_reader_recurse (reader, &sub); byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p); } break; case DBUS_TYPE_UNIX_FD: /* fds can only be passed on a local machine, so byte order must always match */ _dbus_assert_not_reached("attempted to byteswap unix fds which makes no sense"); break; default: _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); break; } if (walk_reader_to_end) _dbus_type_reader_next (reader); else break; } if (new_p) *new_p = p; } /** * Byteswaps the marshaled data in the given value_str. * * @param signature the types in the value_str * @param signature_start where in signature is the signature * @param old_byte_order the old byte order * @param new_byte_order the new byte order * @param value_str the string containing the body * @param value_pos where the values start */ void _dbus_marshal_byteswap (const DBusString *signature, int signature_start, int old_byte_order, int new_byte_order, DBusString *value_str, int value_pos) { DBusTypeReader reader; _dbus_assert (value_pos >= 0); _dbus_assert (value_pos <= _dbus_string_get_length (value_str)); if (old_byte_order == new_byte_order) return; _dbus_type_reader_init_types_only (&reader, signature, signature_start); byteswap_body_helper (&reader, TRUE, old_byte_order, new_byte_order, _dbus_string_get_data_len (value_str, value_pos, 0), NULL); } /** @} */ /* Tests in dbus-marshal-byteswap-util.c */ dbus-1.10.6/dbus/dbus-marshal-header.h0000644000175000017500000001600312602773110017453 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-header.h Managing marshaling/demarshaling of message headers * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_MARSHAL_HEADER_H #define DBUS_MARSHAL_HEADER_H #include #include typedef struct DBusHeader DBusHeader; typedef struct DBusHeaderField DBusHeaderField; #define _DBUS_HEADER_FIELD_VALUE_UNKNOWN -1 #define _DBUS_HEADER_FIELD_VALUE_NONEXISTENT -2 /** * Cached information about a header field in the message */ struct DBusHeaderField { int value_pos; /**< Position of field value, or -1/-2 */ }; /** * Message header data and some cached details of it. */ struct DBusHeader { DBusString data; /**< Header network data, stored * separately from body so we can * independently realloc it. */ DBusHeaderField fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location * of each field in header */ dbus_uint32_t padding : 3; /**< bytes of alignment in header */ dbus_uint32_t byte_order : 8; /**< byte order of header */ }; dbus_bool_t _dbus_header_init (DBusHeader *header); void _dbus_header_free (DBusHeader *header); void _dbus_header_reinit (DBusHeader *header); dbus_bool_t _dbus_header_create (DBusHeader *header, int byte_order, int type, const char *destination, const char *path, const char *interface, const char *member, const char *error_name); dbus_bool_t _dbus_header_copy (const DBusHeader *header, DBusHeader *dest); int _dbus_header_get_message_type (DBusHeader *header); void _dbus_header_set_serial (DBusHeader *header, dbus_uint32_t serial); dbus_uint32_t _dbus_header_get_serial (DBusHeader *header); void _dbus_header_update_lengths (DBusHeader *header, int body_len); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_header_set_field_basic (DBusHeader *header, int field, int type, const void *value); dbus_bool_t _dbus_header_get_field_basic (DBusHeader *header, int field, int type, void *value); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_header_get_field_raw (DBusHeader *header, int field, const DBusString **str, int *pos); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_header_delete_field (DBusHeader *header, int field); void _dbus_header_toggle_flag (DBusHeader *header, dbus_uint32_t flag, dbus_bool_t value); dbus_bool_t _dbus_header_get_flag (DBusHeader *header, dbus_uint32_t flag); dbus_bool_t _dbus_header_ensure_signature (DBusHeader *header, DBusString **type_str, int *type_pos); dbus_bool_t _dbus_header_have_message_untrusted (int max_message_length, DBusValidity *validity, int *byte_order, int *fields_array_len, int *header_len, int *body_len, const DBusString *str, int start, int len); dbus_bool_t _dbus_header_load (DBusHeader *header, DBusValidationMode mode, DBusValidity *validity, int byte_order, int fields_array_len, int header_len, int body_len, const DBusString *str, int start, int len); void _dbus_header_byteswap (DBusHeader *header, int new_order); DBUS_PRIVATE_EXPORT char _dbus_header_get_byte_order (const DBusHeader *header); #endif /* DBUS_MARSHAL_HEADER_H */ dbus-1.10.6/dbus/dbus-marshal-header.c0000644000175000017500000013314412602773110017454 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-marshal-header.c Managing marshaling/demarshaling of message headers * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus/dbus-shared.h" #include "dbus-marshal-header.h" #include "dbus-marshal-recursive.h" #include "dbus-marshal-byteswap.h" /** * @addtogroup DBusMarshal * * @{ */ /* Not thread locked, but strictly const/read-only so should be OK */ /** Static #DBusString containing the signature of a message header */ _DBUS_STRING_DEFINE_STATIC(_dbus_header_signature_str, DBUS_HEADER_SIGNATURE); /** Static #DBusString containing the local interface */ _DBUS_STRING_DEFINE_STATIC(_dbus_local_interface_str, DBUS_INTERFACE_LOCAL); /** Static #DBusString containing the local path */ _DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str, DBUS_PATH_LOCAL); /** Offset from start of _dbus_header_signature_str to the signature of the fields array */ #define FIELDS_ARRAY_SIGNATURE_OFFSET 6 /** Offset from start of _dbus_header_signature_str to the signature of an element of the fields array */ #define FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET 7 /** Offset to byte order from start of header */ #define BYTE_ORDER_OFFSET 0 /** Offset to type from start of header */ #define TYPE_OFFSET 1 /** Offset to flags from start of header */ #define FLAGS_OFFSET 2 /** Offset to version from start of header */ #define VERSION_OFFSET 3 /** Offset to body length from start of header */ #define BODY_LENGTH_OFFSET 4 /** Offset to client serial from start of header */ #define SERIAL_OFFSET 8 /** Offset to fields array length from start of header */ #define FIELDS_ARRAY_LENGTH_OFFSET 12 /** Offset to first field in header */ #define FIRST_FIELD_OFFSET 16 typedef struct { unsigned char code; /**< the field code */ unsigned char type; /**< the value type */ } HeaderFieldType; static const HeaderFieldType _dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = { { DBUS_HEADER_FIELD_INVALID, DBUS_TYPE_INVALID }, { DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH }, { DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32 }, { DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE }, { DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32 } }; /** Macro to look up the correct type for a field */ #define EXPECTED_TYPE_OF_FIELD(field) (_dbus_header_field_types[field].type) /** The most padding we could ever need for a header */ #define MAX_POSSIBLE_HEADER_PADDING 7 static dbus_bool_t reserve_header_padding (DBusHeader *header) { _dbus_assert (header->padding <= MAX_POSSIBLE_HEADER_PADDING); if (!_dbus_string_lengthen (&header->data, MAX_POSSIBLE_HEADER_PADDING - header->padding)) return FALSE; header->padding = MAX_POSSIBLE_HEADER_PADDING; return TRUE; } static void correct_header_padding (DBusHeader *header) { int unpadded_len; _dbus_assert (header->padding == 7); _dbus_string_shorten (&header->data, header->padding); unpadded_len = _dbus_string_get_length (&header->data); if (!_dbus_string_align_length (&header->data, 8)) _dbus_assert_not_reached ("couldn't pad header though enough padding was preallocated"); header->padding = _dbus_string_get_length (&header->data) - unpadded_len; } /** Compute the end of the header, ignoring padding */ #define HEADER_END_BEFORE_PADDING(header) \ (_dbus_string_get_length (&(header)->data) - (header)->padding) /** * Invalidates all fields in the cache. This may be used when the * cache is totally uninitialized (contains junk) so should not * look at what's in there now. * * @param header the header */ static void _dbus_header_cache_invalidate_all (DBusHeader *header) { int i; i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_UNKNOWN; ++i; } } /** * Caches one field * * @param header the header * @param field_code the field * @param variant_reader the reader for the variant in the field */ static void _dbus_header_cache_one (DBusHeader *header, int field_code, DBusTypeReader *variant_reader) { header->fields[field_code].value_pos = _dbus_type_reader_get_value_pos (variant_reader); #if 0 _dbus_verbose ("cached value_pos %d for field %d\n", header->fields[field_code].value_pos, field_code) #endif } /** * Returns the header's byte order. * * @param header the header * @returns the byte order */ char _dbus_header_get_byte_order (const DBusHeader *header) { _dbus_assert (_dbus_string_get_length (&header->data) > BYTE_ORDER_OFFSET); return (char) _dbus_string_get_byte (&header->data, BYTE_ORDER_OFFSET); } /** * Revalidates the fields cache * * @param header the header */ static void _dbus_header_cache_revalidate (DBusHeader *header) { DBusTypeReader array; DBusTypeReader reader; int i; i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; ++i; } _dbus_type_reader_init (&reader, _dbus_header_get_byte_order (header), &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &header->data, FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (&reader, &array); while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) { DBusTypeReader sub; DBusTypeReader variant; unsigned char field_code; _dbus_type_reader_recurse (&array, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&sub, &field_code); /* Unknown fields should be ignored */ if (field_code > DBUS_HEADER_FIELD_LAST) goto next_field; _dbus_type_reader_next (&sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (&sub, &variant); _dbus_header_cache_one (header, field_code, &variant); next_field: _dbus_type_reader_next (&array); } } /** * Checks for a field, updating the cache if required. * * @param header the header * @param field the field to check * @returns #FALSE if the field doesn't exist */ static dbus_bool_t _dbus_header_cache_check (DBusHeader *header, int field) { _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) _dbus_header_cache_revalidate (header); if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT) return FALSE; return TRUE; } /** * Checks whether a field is known not to exist. It may exist * even if it's not known to exist. * * @param header the header * @param field the field to check * @returns #FALSE if the field definitely doesn't exist */ static dbus_bool_t _dbus_header_cache_known_nonexistent (DBusHeader *header, int field) { _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); return (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT); } /** * Writes a struct of { byte, variant } with the given basic type. * * @param writer the writer (should be ready to write a struct) * @param field the header field * @param type the type of the value * @param value the value as for _dbus_marshal_set_basic() * @returns #FALSE if no memory */ static dbus_bool_t write_basic_field (DBusTypeWriter *writer, int field, int type, const void *value) { DBusTypeWriter sub; DBusTypeWriter variant; int start; int padding; unsigned char field_byte; DBusString contained_type; char buf[2]; start = writer->value_pos; padding = _dbus_string_get_length (writer->value_str) - start; if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, NULL, 0, &sub)) goto append_failed; field_byte = field; if (!_dbus_type_writer_write_basic (&sub, DBUS_TYPE_BYTE, &field_byte)) goto append_failed; buf[0] = type; buf[1] = '\0'; _dbus_string_init_const_len (&contained_type, buf, 1); if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_VARIANT, &contained_type, 0, &variant)) goto append_failed; if (!_dbus_type_writer_write_basic (&variant, type, value)) goto append_failed; if (!_dbus_type_writer_unrecurse (&sub, &variant)) goto append_failed; if (!_dbus_type_writer_unrecurse (writer, &sub)) goto append_failed; return TRUE; append_failed: _dbus_string_delete (writer->value_str, start, _dbus_string_get_length (writer->value_str) - start - padding); return FALSE; } /** * Sets a struct of { byte, variant } with the given basic type. * * @param reader the reader (should be iterating over the array pointing at the field to set) * @param field the header field * @param type the type of the value * @param value the value as for _dbus_marshal_set_basic() * @param realign_root where to realign from * @returns #FALSE if no memory */ static dbus_bool_t set_basic_field (DBusTypeReader *reader, int field, int type, const void *value, const DBusTypeReader *realign_root) { DBusTypeReader sub; DBusTypeReader variant; _dbus_type_reader_recurse (reader, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); #ifndef DBUS_DISABLE_ASSERT { unsigned char v_BYTE; _dbus_type_reader_read_basic (&sub, &v_BYTE); _dbus_assert (((int) v_BYTE) == field); } #endif if (!_dbus_type_reader_next (&sub)) _dbus_assert_not_reached ("no variant field?"); _dbus_type_reader_recurse (&sub, &variant); _dbus_assert (_dbus_type_reader_get_current_type (&variant) == type); if (!_dbus_type_reader_set_basic (&variant, value, realign_root)) return FALSE; return TRUE; } /** * Gets the type of the message. * * @param header the header * @returns the type */ int _dbus_header_get_message_type (DBusHeader *header) { int type; type = _dbus_string_get_byte (&header->data, TYPE_OFFSET); _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); return type; } /** * Sets the serial number of a header. This can only be done once on * a header. * * @param header the header * @param serial the serial */ void _dbus_header_set_serial (DBusHeader *header, dbus_uint32_t serial) { /* we use this function to set the serial on outgoing * messages, and to reset the serial in dbus_message_copy; * this assertion should catch a double-set on outgoing. */ _dbus_assert (_dbus_header_get_serial (header) == 0 || serial == 0); _dbus_marshal_set_uint32 (&header->data, SERIAL_OFFSET, serial, _dbus_header_get_byte_order (header)); } /** * See dbus_message_get_serial() * * @param header the header * @returns the client serial */ dbus_uint32_t _dbus_header_get_serial (DBusHeader *header) { return _dbus_marshal_read_uint32 (&header->data, SERIAL_OFFSET, _dbus_header_get_byte_order (header), NULL); } /** * Re-initializes a header that was previously initialized and never * freed. After this, to make the header valid you have to call * _dbus_header_create(). * * @param header header to re-initialize */ void _dbus_header_reinit (DBusHeader *header) { _dbus_string_set_length (&header->data, 0); header->padding = 0; _dbus_header_cache_invalidate_all (header); } /** * Initializes a header, but doesn't prepare it for use; * to make the header valid, you have to call _dbus_header_create(). * * @param header header to initialize * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_header_init (DBusHeader *header) { if (!_dbus_string_init_preallocated (&header->data, 32)) return FALSE; _dbus_header_reinit (header); return TRUE; } /** * Frees a header. * * @param header the header */ void _dbus_header_free (DBusHeader *header) { _dbus_string_free (&header->data); } /** * Initializes dest with a copy of the given header. * Resets the message serial to 0 on the copy. * * @param header header to copy * @param dest destination for copy * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_header_copy (const DBusHeader *header, DBusHeader *dest) { *dest = *header; if (!_dbus_string_init_preallocated (&dest->data, _dbus_string_get_length (&header->data))) return FALSE; if (!_dbus_string_copy (&header->data, 0, &dest->data, 0)) { _dbus_string_free (&dest->data); return FALSE; } /* Reset the serial */ _dbus_header_set_serial (dest, 0); return TRUE; } /** * Fills in the primary fields of the header, so the header is ready * for use. #NULL may be specified for some or all of the fields to * avoid adding those fields. Some combinations of fields don't make * sense, and passing them in will trigger an assertion failure. * * @param header the header * @param byte_order byte order of the header * @param message_type the message type * @param destination destination field or #NULL * @param path path field or #NULL * @param interface interface field or #NULL * @param member member field or #NULL * @param error_name error name or #NULL * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_header_create (DBusHeader *header, int byte_order, int message_type, const char *destination, const char *path, const char *interface, const char *member, const char *error_name) { unsigned char v_BYTE; dbus_uint32_t v_UINT32; DBusTypeWriter writer; DBusTypeWriter array; _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); _dbus_assert (((interface || message_type != DBUS_MESSAGE_TYPE_SIGNAL) && member) || (error_name) || !(interface || member || error_name)); _dbus_assert (_dbus_string_get_length (&header->data) == 0); if (!reserve_header_padding (header)) return FALSE; _dbus_type_writer_init_values_only (&writer, byte_order, &_dbus_header_signature_str, 0, &header->data, HEADER_END_BEFORE_PADDING (header)); v_BYTE = byte_order; if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, &v_BYTE)) goto oom; v_BYTE = message_type; if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, &v_BYTE)) goto oom; v_BYTE = 0; /* flags */ if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, &v_BYTE)) goto oom; v_BYTE = DBUS_MAJOR_PROTOCOL_VERSION; if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, &v_BYTE)) goto oom; v_UINT32 = 0; /* body length */ if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, &v_UINT32)) goto oom; v_UINT32 = 0; /* serial */ if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, &v_UINT32)) goto oom; if (!_dbus_type_writer_recurse (&writer, DBUS_TYPE_ARRAY, &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &array)) goto oom; /* Marshal all the fields (Marshall Fields?) */ if (path != NULL) { if (!write_basic_field (&array, DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH, &path)) goto oom; } if (destination != NULL) { if (!write_basic_field (&array, DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING, &destination)) goto oom; } if (interface != NULL) { if (!write_basic_field (&array, DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING, &interface)) goto oom; } if (member != NULL) { if (!write_basic_field (&array, DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING, &member)) goto oom; } if (error_name != NULL) { if (!write_basic_field (&array, DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING, &error_name)) goto oom; } if (!_dbus_type_writer_unrecurse (&writer, &array)) goto oom; correct_header_padding (header); return TRUE; oom: _dbus_string_delete (&header->data, 0, _dbus_string_get_length (&header->data) - header->padding); correct_header_padding (header); return FALSE; } /** * Given data long enough to contain the length of the message body * and the fields array, check whether the data is long enough to * contain the entire message (assuming the claimed lengths are * accurate). Also checks that the lengths are in sanity parameters. * * @param max_message_length maximum length of a valid message * @param validity return location for why the data is invalid if it is * @param byte_order return location for byte order * @param fields_array_len return location for claimed fields array length * @param header_len return location for claimed header length * @param body_len return location for claimed body length * @param str the data * @param start start of data, 8-aligned * @param len length of data * @returns #TRUE if the data is long enough for the claimed length, and the lengths were valid */ dbus_bool_t _dbus_header_have_message_untrusted (int max_message_length, DBusValidity *validity, int *byte_order, int *fields_array_len, int *header_len, int *body_len, const DBusString *str, int start, int len) { dbus_uint32_t header_len_unsigned; dbus_uint32_t fields_array_len_unsigned; dbus_uint32_t body_len_unsigned; _dbus_assert (start >= 0); _dbus_assert (start < _DBUS_INT32_MAX / 2); _dbus_assert (len >= 0); _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); *byte_order = _dbus_string_get_byte (str, start + BYTE_ORDER_OFFSET); if (*byte_order != DBUS_LITTLE_ENDIAN && *byte_order != DBUS_BIG_ENDIAN) { *validity = DBUS_INVALID_BAD_BYTE_ORDER; return FALSE; } _dbus_assert (FIELDS_ARRAY_LENGTH_OFFSET + 4 <= len); fields_array_len_unsigned = _dbus_marshal_read_uint32 (str, start + FIELDS_ARRAY_LENGTH_OFFSET, *byte_order, NULL); if (fields_array_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH; return FALSE; } _dbus_assert (BODY_LENGTH_OFFSET + 4 < len); body_len_unsigned = _dbus_marshal_read_uint32 (str, start + BODY_LENGTH_OFFSET, *byte_order, NULL); if (body_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_INSANE_BODY_LENGTH; return FALSE; } header_len_unsigned = FIRST_FIELD_OFFSET + fields_array_len_unsigned; header_len_unsigned = _DBUS_ALIGN_VALUE (header_len_unsigned, 8); /* overflow should be impossible since the lengths aren't allowed to * be huge. */ _dbus_assert (max_message_length < _DBUS_INT32_MAX / 2); if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_MESSAGE_TOO_LONG; return FALSE; } _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT32_MAX); _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT32_MAX); _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT32_MAX); *body_len = body_len_unsigned; *fields_array_len = fields_array_len_unsigned; *header_len = header_len_unsigned; *validity = DBUS_VALID; _dbus_verbose ("have %d bytes, need body %u + header %u = %u\n", len, body_len_unsigned, header_len_unsigned, body_len_unsigned + header_len_unsigned); return (body_len_unsigned + header_len_unsigned) <= (unsigned) len; } static DBusValidity check_mandatory_fields (DBusHeader *header) { #define REQUIRE_FIELD(name) do { if (header->fields[DBUS_HEADER_FIELD_##name].value_pos < 0) return DBUS_INVALID_MISSING_##name; } while (0) switch (_dbus_header_get_message_type (header)) { case DBUS_MESSAGE_TYPE_SIGNAL: REQUIRE_FIELD (INTERFACE); /* FALL THRU - signals also require the path and member */ case DBUS_MESSAGE_TYPE_METHOD_CALL: REQUIRE_FIELD (PATH); REQUIRE_FIELD (MEMBER); break; case DBUS_MESSAGE_TYPE_ERROR: REQUIRE_FIELD (ERROR_NAME); REQUIRE_FIELD (REPLY_SERIAL); break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: REQUIRE_FIELD (REPLY_SERIAL); break; default: /* other message types allowed but ignored */ break; } return DBUS_VALID; } static DBusValidity load_and_validate_field (DBusHeader *header, int field, DBusTypeReader *variant_reader) { int type; int expected_type; const DBusString *value_str; int value_pos; int str_data_pos; dbus_uint32_t v_UINT32; int bad_string_code; dbus_bool_t (* string_validation_func) (const DBusString *str, int start, int len); /* Supposed to have been checked already */ _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); /* Before we can cache a field, we need to know it has the right type */ type = _dbus_type_reader_get_current_type (variant_reader); _dbus_assert (_dbus_header_field_types[field].code == field); expected_type = EXPECTED_TYPE_OF_FIELD (field); if (type != expected_type) { _dbus_verbose ("Field %d should have type %d but has %d\n", field, expected_type, type); return DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE; } /* If the field was provided twice, we aren't happy */ if (header->fields[field].value_pos >= 0) { _dbus_verbose ("Header field %d seen a second time\n", field); return DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE; } /* Now we can cache and look at the field content */ _dbus_verbose ("initially caching field %d\n", field); _dbus_header_cache_one (header, field, variant_reader); string_validation_func = NULL; /* make compiler happy that all this is initialized */ v_UINT32 = 0; value_str = NULL; value_pos = -1; str_data_pos = -1; bad_string_code = DBUS_VALID; if (expected_type == DBUS_TYPE_UINT32) { _dbus_header_get_field_basic (header, field, expected_type, &v_UINT32); } else if (expected_type == DBUS_TYPE_STRING || expected_type == DBUS_TYPE_OBJECT_PATH || expected_type == DBUS_TYPE_SIGNATURE) { _dbus_header_get_field_raw (header, field, &value_str, &value_pos); str_data_pos = _DBUS_ALIGN_VALUE (value_pos, 4) + 4; } else { _dbus_assert_not_reached ("none of the known fields should have this type"); } switch (field) { case DBUS_HEADER_FIELD_DESTINATION: string_validation_func = _dbus_validate_bus_name; bad_string_code = DBUS_INVALID_BAD_DESTINATION; break; case DBUS_HEADER_FIELD_INTERFACE: string_validation_func = _dbus_validate_interface; bad_string_code = DBUS_INVALID_BAD_INTERFACE; if (_dbus_string_equal_substring (&_dbus_local_interface_str, 0, _dbus_string_get_length (&_dbus_local_interface_str), value_str, str_data_pos)) { _dbus_verbose ("Message is on the local interface\n"); return DBUS_INVALID_USES_LOCAL_INTERFACE; } break; case DBUS_HEADER_FIELD_MEMBER: string_validation_func = _dbus_validate_member; bad_string_code = DBUS_INVALID_BAD_MEMBER; break; case DBUS_HEADER_FIELD_ERROR_NAME: string_validation_func = _dbus_validate_error_name; bad_string_code = DBUS_INVALID_BAD_ERROR_NAME; break; case DBUS_HEADER_FIELD_SENDER: string_validation_func = _dbus_validate_bus_name; bad_string_code = DBUS_INVALID_BAD_SENDER; break; case DBUS_HEADER_FIELD_PATH: /* OBJECT_PATH was validated generically due to its type */ string_validation_func = NULL; if (_dbus_string_equal_substring (&_dbus_local_path_str, 0, _dbus_string_get_length (&_dbus_local_path_str), value_str, str_data_pos)) { _dbus_verbose ("Message is from the local path\n"); return DBUS_INVALID_USES_LOCAL_PATH; } break; case DBUS_HEADER_FIELD_REPLY_SERIAL: /* Can't be 0 */ if (v_UINT32 == 0) { return DBUS_INVALID_BAD_SERIAL; } break; case DBUS_HEADER_FIELD_UNIX_FDS: /* Every value makes sense */ break; case DBUS_HEADER_FIELD_SIGNATURE: /* SIGNATURE validated generically due to its type */ string_validation_func = NULL; break; default: _dbus_assert_not_reached ("unknown field shouldn't be seen here"); break; } if (string_validation_func) { dbus_uint32_t len; _dbus_assert (bad_string_code != DBUS_VALID); len = _dbus_marshal_read_uint32 (value_str, value_pos, _dbus_header_get_byte_order (header), NULL); #if 0 _dbus_verbose ("Validating string header field; code %d if fails\n", bad_string_code); #endif if (!(*string_validation_func) (value_str, str_data_pos, len)) return bad_string_code; } return DBUS_VALID; } /** * Creates a message header from potentially-untrusted data. The * return value is #TRUE if there was enough memory and the data was * valid. If it returns #TRUE, the header will be created. If it * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, * then there wasn't enough memory. If it returns #FALSE * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was * invalid. * * The byte_order, fields_array_len, and body_len args should be from * _dbus_header_have_message_untrusted(). Validation performed in * _dbus_header_have_message_untrusted() is assumed to have been * already done. * * @param header the header (must be initialized) * @param mode whether to do validation * @param validity return location for invalidity reason * @param byte_order byte order from header * @param fields_array_len claimed length of fields array * @param body_len claimed length of body * @param header_len claimed length of header * @param str a string * @param start start of header, 8-aligned * @param len length of string to look at * @returns #FALSE if no memory or data was invalid, #TRUE otherwise */ dbus_bool_t _dbus_header_load (DBusHeader *header, DBusValidationMode mode, DBusValidity *validity, int byte_order, int fields_array_len, int header_len, int body_len, const DBusString *str, int start, int len) { int leftover; DBusValidity v; DBusTypeReader reader; DBusTypeReader array_reader; unsigned char v_byte; dbus_uint32_t v_uint32; dbus_uint32_t serial; int padding_start; int padding_len; int i; _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); _dbus_assert (header_len <= len); _dbus_assert (_dbus_string_get_length (&header->data) == 0); if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0)) { _dbus_verbose ("Failed to copy buffer into new header\n"); *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; return FALSE; } if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { leftover = len - header_len - body_len - start; } else { v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0, byte_order, &leftover, str, start, len); if (v != DBUS_VALID) { *validity = v; goto invalid; } } _dbus_assert (leftover < len); padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len); padding_start = start + FIRST_FIELD_OFFSET + fields_array_len; _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8)); _dbus_assert (start + header_len == padding_start + padding_len); if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { if (!_dbus_string_validate_nul (str, padding_start, padding_len)) { *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; goto invalid; } } header->padding = padding_len; if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { *validity = DBUS_VALID; return TRUE; } /* We now know the data is well-formed, but we have to check that * it's valid. */ _dbus_type_reader_init (&reader, byte_order, &_dbus_header_signature_str, 0, str, start); /* BYTE ORDER */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); _dbus_assert (v_byte == byte_order); /* MESSAGE TYPE */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown message types are supposed to be ignored, so only validation here is * that it isn't invalid */ if (v_byte == DBUS_MESSAGE_TYPE_INVALID) { *validity = DBUS_INVALID_BAD_MESSAGE_TYPE; goto invalid; } /* FLAGS */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown flags should be ignored */ /* PROTOCOL VERSION */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION) { *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION; goto invalid; } /* BODY LENGTH */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET); _dbus_type_reader_read_basic (&reader, &v_uint32); _dbus_type_reader_next (&reader); _dbus_assert (body_len == (signed) v_uint32); /* SERIAL */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET); _dbus_type_reader_read_basic (&reader, &serial); _dbus_type_reader_next (&reader); if (serial == 0) { *validity = DBUS_INVALID_BAD_SERIAL; goto invalid; } _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (&reader, &array_reader); while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID) { DBusTypeReader struct_reader; DBusTypeReader variant_reader; unsigned char field_code; _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (&array_reader, &struct_reader); _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&struct_reader, &field_code); _dbus_type_reader_next (&struct_reader); if (field_code == DBUS_HEADER_FIELD_INVALID) { _dbus_verbose ("invalid header field code\n"); *validity = DBUS_INVALID_HEADER_FIELD_CODE; goto invalid; } if (field_code > DBUS_HEADER_FIELD_LAST) { _dbus_verbose ("unknown header field code %d, skipping\n", field_code); goto next_field; } _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (&struct_reader, &variant_reader); v = load_and_validate_field (header, field_code, &variant_reader); if (v != DBUS_VALID) { _dbus_verbose ("Field %d was invalid\n", field_code); *validity = v; goto invalid; } next_field: _dbus_type_reader_next (&array_reader); } /* Anything we didn't fill in is now known not to exist */ i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; ++i; } v = check_mandatory_fields (header); if (v != DBUS_VALID) { _dbus_verbose ("Mandatory fields were missing, code %d\n", v); *validity = v; goto invalid; } *validity = DBUS_VALID; return TRUE; invalid: _dbus_string_set_length (&header->data, 0); return FALSE; } /** * Fills in the correct body length. * * @param header the header * @param body_len the length of the body */ void _dbus_header_update_lengths (DBusHeader *header, int body_len) { _dbus_marshal_set_uint32 (&header->data, BODY_LENGTH_OFFSET, body_len, _dbus_header_get_byte_order (header)); } /** * Try to find the given field. * * @param header the header * @param field the field code * @param reader a type reader; on success this is left pointing at the struct * (uv) for the field, while on failure it is left pointing into empty space * at the end of the header fields * @param realign_root another type reader; on success or failure it is left * pointing to the beginning of the array of fields (i.e. the thing that might * need realigning) * @returns #TRUE on success */ static dbus_bool_t find_field_for_modification (DBusHeader *header, int field, DBusTypeReader *reader, DBusTypeReader *realign_root) { dbus_bool_t retval; retval = FALSE; _dbus_type_reader_init (realign_root, _dbus_header_get_byte_order (header), &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &header->data, FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (realign_root, reader); while (_dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID) { DBusTypeReader sub; unsigned char field_code; _dbus_type_reader_recurse (reader, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&sub, &field_code); if (field_code == (unsigned) field) { _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_STRUCT); retval = TRUE; goto done; } _dbus_type_reader_next (reader); } done: return retval; } /** * Sets the value of a field with basic type. If the value is a string * value, it isn't allowed to be #NULL. If the field doesn't exist, * it will be created. * * @param header the header * @param field the field to set * @param type the type of the value * @param value the value as for _dbus_marshal_set_basic() * @returns #FALSE if no memory */ dbus_bool_t _dbus_header_set_field_basic (DBusHeader *header, int field, int type, const void *value) { _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); if (!reserve_header_padding (header)) return FALSE; /* If the field exists we set, otherwise we append */ if (_dbus_header_cache_check (header, field)) { DBusTypeReader reader; DBusTypeReader realign_root; if (!find_field_for_modification (header, field, &reader, &realign_root)) _dbus_assert_not_reached ("field was marked present in cache but wasn't found"); if (!set_basic_field (&reader, field, type, value, &realign_root)) return FALSE; } else { DBusTypeWriter writer; DBusTypeWriter array; _dbus_type_writer_init_values_only (&writer, _dbus_header_get_byte_order (header), &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &header->data, FIELDS_ARRAY_LENGTH_OFFSET); /* recurse into array without creating a new length, and jump to * end of array. */ if (!_dbus_type_writer_append_array (&writer, &_dbus_header_signature_str, FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET, &array)) _dbus_assert_not_reached ("recurse into ARRAY should not have used memory"); _dbus_assert (array.u.array.len_pos == FIELDS_ARRAY_LENGTH_OFFSET); _dbus_assert (array.u.array.start_pos == FIRST_FIELD_OFFSET); _dbus_assert (array.value_pos == HEADER_END_BEFORE_PADDING (header)); if (!write_basic_field (&array, field, type, value)) return FALSE; if (!_dbus_type_writer_unrecurse (&writer, &array)) _dbus_assert_not_reached ("unrecurse from ARRAY should not have used memory"); } correct_header_padding (header); /* We could be smarter about this (only invalidate fields after the * one we modified, or even only if the one we modified changed * length). But this hack is a start. */ _dbus_header_cache_invalidate_all (header); return TRUE; } /** * Gets the value of a field with basic type. If the field * doesn't exist, returns #FALSE, otherwise returns #TRUE. * * @param header the header * @param field the field to get * @param type the type of the value * @param value the value as for _dbus_marshal_read_basic() * @returns #FALSE if the field doesn't exist */ dbus_bool_t _dbus_header_get_field_basic (DBusHeader *header, int field, int type, void *value) { _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); _dbus_assert (_dbus_header_field_types[field].code == field); /* in light of this you might ask why the type is passed in; * the only rationale I can think of is so the caller has * to specify its expectation and breaks if we change it */ _dbus_assert (type == EXPECTED_TYPE_OF_FIELD (field)); if (!_dbus_header_cache_check (header, field)) return FALSE; _dbus_assert (header->fields[field].value_pos >= 0); _dbus_marshal_read_basic (&header->data, header->fields[field].value_pos, type, value, _dbus_header_get_byte_order (header), NULL); return TRUE; } /** * Gets the raw marshaled data for a field. If the field doesn't * exist, returns #FALSE, otherwise returns #TRUE. Returns the start * of the marshaled data, i.e. usually the byte where the length * starts (for strings and arrays) or for basic types just the value * itself. * * @param header the header * @param field the field to get * @param str return location for the data string * @param pos return location for start of field value * @returns #FALSE if the field doesn't exist */ dbus_bool_t _dbus_header_get_field_raw (DBusHeader *header, int field, const DBusString **str, int *pos) { if (!_dbus_header_cache_check (header, field)) return FALSE; if (str) *str = &header->data; if (pos) *pos = header->fields[field].value_pos; return TRUE; } /** * Deletes a field, if it exists. * * @param header the header * @param field the field to delete * @returns #FALSE if no memory */ dbus_bool_t _dbus_header_delete_field (DBusHeader *header, int field) { DBusTypeReader reader; DBusTypeReader realign_root; if (_dbus_header_cache_known_nonexistent (header, field)) return TRUE; /* nothing to do */ /* Scan to the field we want, delete and realign, reappend * padding. Field may turn out not to exist. */ if (!find_field_for_modification (header, field, &reader, &realign_root)) return TRUE; /* nothing to do */ if (!reserve_header_padding (header)) return FALSE; if (!_dbus_type_reader_delete (&reader, &realign_root)) return FALSE; correct_header_padding (header); _dbus_header_cache_invalidate_all (header); _dbus_assert (!_dbus_header_cache_check (header, field)); /* Expensive assertion ... */ return TRUE; } /** * Toggles a message flag bit, turning on the bit if value = TRUE and * flipping it off if value = FALSE. * * @param header the header * @param flag the message flag to toggle * @param value toggle on or off */ void _dbus_header_toggle_flag (DBusHeader *header, dbus_uint32_t flag, dbus_bool_t value) { unsigned char *flags_p; flags_p = _dbus_string_get_data_len (&header->data, FLAGS_OFFSET, 1); if (value) *flags_p |= flag; else *flags_p &= ~flag; } /** * Gets a message flag bit, returning TRUE if the bit is set. * * @param header the header * @param flag the message flag to get * @returns #TRUE if the flag is set */ dbus_bool_t _dbus_header_get_flag (DBusHeader *header, dbus_uint32_t flag) { const unsigned char *flags_p; flags_p = _dbus_string_get_const_data_len (&header->data, FLAGS_OFFSET, 1); return (*flags_p & flag) != 0; } /** * Swaps the header into the given order if required. * * @param header the header * @param new_order the new byte order */ void _dbus_header_byteswap (DBusHeader *header, int new_order) { char byte_order; byte_order = _dbus_header_get_byte_order (header); if (byte_order == new_order) return; _dbus_marshal_byteswap (&_dbus_header_signature_str, 0, byte_order, new_order, &header->data, 0); _dbus_string_set_byte (&header->data, BYTE_ORDER_OFFSET, new_order); } /** @} */ dbus-1.10.6/dbus/dbus-keyring.h0000644000175000017500000000424512602773110016253 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-keyring.h Store secret cookies in your homedir * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_KEYRING_H #define DBUS_KEYRING_H #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusKeyring DBusKeyring; DBusKeyring* _dbus_keyring_new_for_credentials (DBusCredentials *credentials, const DBusString *context, DBusError *error); DBusKeyring* _dbus_keyring_ref (DBusKeyring *keyring); void _dbus_keyring_unref (DBusKeyring *keyring); dbus_bool_t _dbus_keyring_validate_context (const DBusString *context); int _dbus_keyring_get_best_key (DBusKeyring *keyring, DBusError *error); dbus_bool_t _dbus_keyring_is_for_credentials (DBusKeyring *keyring, DBusCredentials *credentials); dbus_bool_t _dbus_keyring_get_hex_key (DBusKeyring *keyring, int key_id, DBusString *hex_key); DBUS_END_DECLS #endif /* DBUS_KEYRING_H */ dbus-1.10.6/dbus/dbus-keyring.c0000644000175000017500000007473112602773110016255 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-keyring.c Store secret cookies in your homedir * * Copyright (C) 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-keyring.h" #include "dbus-protocol.h" #include #include #include /** * @defgroup DBusKeyring keyring class * @ingroup DBusInternals * @brief DBusKeyring data structure * * Types and functions related to DBusKeyring. DBusKeyring is intended * to manage cookies used to authenticate clients to servers. This is * essentially the "verify that client can read the user's homedir" * authentication mechanism. Both client and server must have access * to the homedir. * * The secret keys are not kept in locked memory, and are written to a * file in the user's homedir. However they are transient (only used * by a single server instance for a fixed period of time, then * discarded). Also, the keys are not sent over the wire. * * @todo there's a memory leak on some codepath in here, I saw it once * when running make check - probably some specific initial cookies * present in the cookie file, then depending on what we do with them. */ /** * @defgroup DBusKeyringInternals DBusKeyring implementation details * @ingroup DBusInternals * @brief DBusKeyring implementation details * * The guts of DBusKeyring. * * @{ */ /** The maximum age of a key before we create a new key to use in * challenges. This isn't super-reliably enforced, since system * clocks can change or be wrong, but we make a best effort to only * use keys for a short time. */ #define NEW_KEY_TIMEOUT_SECONDS (60*5) /** * The time after which we drop a key from the secrets file. * The EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS is the minimum * time window a client has to complete authentication. */ #define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2)) /** * The maximum amount of time a key can be in the future. */ #define MAX_TIME_TRAVEL_SECONDS (60*5) /** * Maximum number of keys in the keyring before * we just ignore the rest */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #define MAX_KEYS_IN_FILE 10 #else #define MAX_KEYS_IN_FILE 256 #endif /** * A single key from the cookie file */ typedef struct { dbus_int32_t id; /**< identifier used to refer to the key */ long creation_time; /**< when the key was generated, * as unix timestamp. signed long * matches struct timeval. */ DBusString secret; /**< the actual key */ } DBusKey; /** * @brief Internals of DBusKeyring. * * DBusKeyring internals. DBusKeyring is an opaque object, it must be * used via accessor functions. */ struct DBusKeyring { int refcount; /**< Reference count */ DBusString directory; /**< Directory the below two items are inside */ DBusString filename; /**< Keyring filename */ DBusString filename_lock; /**< Name of lockfile */ DBusKey *keys; /**< Keys loaded from the file */ int n_keys; /**< Number of keys */ DBusCredentials *credentials; /**< Credentials containing user the keyring is for */ }; static DBusKeyring* _dbus_keyring_new (void) { DBusKeyring *keyring; keyring = dbus_new0 (DBusKeyring, 1); if (keyring == NULL) goto out_0; if (!_dbus_string_init (&keyring->directory)) goto out_1; if (!_dbus_string_init (&keyring->filename)) goto out_2; if (!_dbus_string_init (&keyring->filename_lock)) goto out_3; keyring->refcount = 1; keyring->keys = NULL; keyring->n_keys = 0; return keyring; out_3: _dbus_string_free (&keyring->filename); out_2: _dbus_string_free (&keyring->directory); out_1: dbus_free (keyring); out_0: return NULL; } static void free_keys (DBusKey *keys, int n_keys) { int i; /* should be safe for args NULL, 0 */ i = 0; while (i < n_keys) { _dbus_string_free (&keys[i].secret); ++i; } dbus_free (keys); } /* Our locking scheme is highly unreliable. However, there is * unfortunately no reliable locking scheme in user home directories; * between bugs in Linux NFS, people using Tru64 or other total crap * NFS, AFS, random-file-system-of-the-week, and so forth, fcntl() in * homedirs simply generates tons of bug reports. This has been * learned through hard experience with GConf, unfortunately. * * This bad hack might work better for the kind of lock we have here, * which we don't expect to hold for any length of time. Crashing * while we hold it should be unlikely, and timing out such that we * delete a stale lock should also be unlikely except when the * filesystem is running really slowly. Stuff might break in corner * cases but as long as it's not a security-level breakage it should * be OK. */ /** Maximum number of timeouts waiting for lock before we decide it's stale */ #define MAX_LOCK_TIMEOUTS 32 /** Length of each timeout while waiting for a lock */ #define LOCK_TIMEOUT_MILLISECONDS 250 static dbus_bool_t _dbus_keyring_lock (DBusKeyring *keyring) { int n_timeouts; n_timeouts = 0; while (n_timeouts < MAX_LOCK_TIMEOUTS) { DBusError error = DBUS_ERROR_INIT; if (_dbus_create_file_exclusively (&keyring->filename_lock, &error)) break; _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n", LOCK_TIMEOUT_MILLISECONDS, error.message); dbus_error_free (&error); _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS); ++n_timeouts; } if (n_timeouts == MAX_LOCK_TIMEOUTS) { DBusError error = DBUS_ERROR_INIT; _dbus_verbose ("Lock file timed out %d times, assuming stale\n", n_timeouts); if (!_dbus_delete_file (&keyring->filename_lock, &error)) { _dbus_verbose ("Couldn't delete old lock file: %s\n", error.message); dbus_error_free (&error); return FALSE; } if (!_dbus_create_file_exclusively (&keyring->filename_lock, &error)) { _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n", error.message); dbus_error_free (&error); return FALSE; } } return TRUE; } static void _dbus_keyring_unlock (DBusKeyring *keyring) { DBusError error = DBUS_ERROR_INIT; if (!_dbus_delete_file (&keyring->filename_lock, &error)) { _dbus_warn ("Failed to delete lock file: %s\n", error.message); dbus_error_free (&error); } } static DBusKey* find_key_by_id (DBusKey *keys, int n_keys, int id) { int i; i = 0; while (i < n_keys) { if (keys[i].id == id) return &keys[i]; ++i; } return NULL; } static dbus_bool_t add_new_key (DBusKey **keys_p, int *n_keys_p, DBusError *error) { DBusKey *new; DBusString bytes; int id; long timestamp; const unsigned char *s; dbus_bool_t retval; DBusKey *keys; int n_keys; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&bytes)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } keys = *keys_p; n_keys = *n_keys_p; retval = FALSE; /* Generate an integer ID and then the actual key. */ retry: if (!_dbus_generate_random_bytes (&bytes, 4, error)) goto out; s = (const unsigned char*) _dbus_string_get_const_data (&bytes); id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); if (id < 0) id = - id; _dbus_assert (id >= 0); if (find_key_by_id (keys, n_keys, id) != NULL) { _dbus_string_set_length (&bytes, 0); _dbus_verbose ("Key ID %d already existed, trying another one\n", id); goto retry; } _dbus_verbose ("Creating key with ID %d\n", id); #define KEY_LENGTH_BYTES 24 _dbus_string_set_length (&bytes, 0); if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES, error)) { goto out; } new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); if (new == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } keys = new; *keys_p = keys; /* otherwise *keys_p ends up invalid */ n_keys += 1; if (!_dbus_string_init (&keys[n_keys-1].secret)) { n_keys -= 1; /* we don't want to free the one we didn't init */ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } _dbus_get_real_time (×tamp, NULL); keys[n_keys-1].id = id; keys[n_keys-1].creation_time = timestamp; if (!_dbus_string_move (&bytes, 0, &keys[n_keys-1].secret, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&keys[n_keys-1].secret); n_keys -= 1; goto out; } retval = TRUE; out: *n_keys_p = n_keys; _dbus_string_free (&bytes); return retval; } /** * Reloads the keyring file, optionally adds one new key to the file, * removes all expired keys from the file iff a key was added, then * resaves the file. Stores the keys from the file in keyring->keys. * Note that the file is only resaved (written to) if a key is added, * this means that only servers ever write to the file and need to * lock it, which avoids a lot of lock contention at login time and * such. * * @param keyring the keyring * @param add_new #TRUE to add a new key to the file, expire keys, and resave * @param error return location for errors * @returns #FALSE on failure */ static dbus_bool_t _dbus_keyring_reload (DBusKeyring *keyring, dbus_bool_t add_new, DBusError *error) { DBusString contents; DBusString line; dbus_bool_t retval; dbus_bool_t have_lock; DBusKey *keys; int n_keys; int i; long now; DBusError tmp_error; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error)) return FALSE; if (!_dbus_string_init (&contents)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } if (!_dbus_string_init (&line)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&contents); return FALSE; } keys = NULL; n_keys = 0; retval = FALSE; have_lock = FALSE; _dbus_get_real_time (&now, NULL); if (add_new) { if (!_dbus_keyring_lock (keyring)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not lock keyring file to add to it"); goto out; } have_lock = TRUE; } dbus_error_init (&tmp_error); if (!_dbus_file_get_contents (&contents, &keyring->filename, &tmp_error)) { _dbus_verbose ("Failed to load keyring file: %s\n", tmp_error.message); /* continue with empty keyring file, so we recreate it */ dbus_error_free (&tmp_error); } if (!_dbus_string_validate_ascii (&contents, 0, _dbus_string_get_length (&contents))) { _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n"); _dbus_string_set_length (&contents, 0); } /* FIXME this is badly inefficient for large keyring files * (not that large keyring files exist outside of test suites) */ while (_dbus_string_pop_line (&contents, &line)) { int next; long val; int id; long timestamp; int len; int end; DBusKey *new; /* Don't load more than the max. */ if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE)) break; next = 0; if (!_dbus_string_parse_int (&line, 0, &val, &next)) { _dbus_verbose ("could not parse secret key ID at start of line\n"); continue; } if (val > _DBUS_INT32_MAX || val < 0) { _dbus_verbose ("invalid secret key ID at start of line\n"); continue; } id = val; _dbus_string_skip_blank (&line, next, &next); if (!_dbus_string_parse_int (&line, next, ×tamp, &next)) { _dbus_verbose ("could not parse secret key timestamp\n"); continue; } if (timestamp < 0 || (now + MAX_TIME_TRAVEL_SECONDS) < timestamp || (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp) { _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n", now - timestamp, timestamp, now); continue; } _dbus_string_skip_blank (&line, next, &next); len = _dbus_string_get_length (&line); if ((len - next) == 0) { _dbus_verbose ("no secret key after ID and timestamp\n"); continue; } /* We have all three parts */ new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); if (new == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } keys = new; n_keys += 1; if (!_dbus_string_init (&keys[n_keys-1].secret)) { n_keys -= 1; /* we don't want to free the one we didn't init */ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } keys[n_keys-1].id = id; keys[n_keys-1].creation_time = timestamp; if (!_dbus_string_hex_decode (&line, next, &end, &keys[n_keys-1].secret, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } if (_dbus_string_get_length (&line) != end) { _dbus_verbose ("invalid hex encoding in keyring file\n"); _dbus_string_free (&keys[n_keys - 1].secret); n_keys -= 1; continue; } } _dbus_verbose ("Successfully loaded %d existing keys\n", n_keys); if (add_new) { if (!add_new_key (&keys, &n_keys, error)) { _dbus_verbose ("Failed to generate new key: %s\n", error ? error->message : "(unknown)"); goto out; } _dbus_string_set_length (&contents, 0); i = 0; while (i < n_keys) { if (!_dbus_string_append_int (&contents, keys[i].id)) goto nomem; if (!_dbus_string_append_byte (&contents, ' ')) goto nomem; if (!_dbus_string_append_int (&contents, keys[i].creation_time)) goto nomem; if (!_dbus_string_append_byte (&contents, ' ')) goto nomem; if (!_dbus_string_hex_encode (&keys[i].secret, 0, &contents, _dbus_string_get_length (&contents))) goto nomem; if (!_dbus_string_append_byte (&contents, '\n')) goto nomem; ++i; continue; nomem: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto out; } if (!_dbus_string_save_to_file (&contents, &keyring->filename, FALSE, error)) goto out; } if (keyring->keys) free_keys (keyring->keys, keyring->n_keys); keyring->keys = keys; keyring->n_keys = n_keys; keys = NULL; n_keys = 0; retval = TRUE; out: if (have_lock) _dbus_keyring_unlock (keyring); if (! ((retval == TRUE && (error == NULL || error->name == NULL)) || (retval == FALSE && (error == NULL || error->name != NULL)))) { if (error && error->name) _dbus_verbose ("error is %s: %s\n", error->name, error->message); _dbus_warn ("returning %d but error pointer %p name %s\n", retval, error, error->name ? error->name : "(none)"); _dbus_assert_not_reached ("didn't handle errors properly"); } if (keys != NULL) { i = 0; while (i < n_keys) { _dbus_string_zero (&keys[i].secret); _dbus_string_free (&keys[i].secret); ++i; } dbus_free (keys); } _dbus_string_free (&contents); _dbus_string_free (&line); return retval; } /** @} */ /* end of internals */ /** * @addtogroup DBusKeyring * * @{ */ /** * Increments reference count of the keyring * * @param keyring the keyring * @returns the keyring */ DBusKeyring * _dbus_keyring_ref (DBusKeyring *keyring) { keyring->refcount += 1; return keyring; } /** * Decrements refcount and finalizes if it reaches * zero. * * @param keyring the keyring */ void _dbus_keyring_unref (DBusKeyring *keyring) { keyring->refcount -= 1; if (keyring->refcount == 0) { if (keyring->credentials) _dbus_credentials_unref (keyring->credentials); _dbus_string_free (&keyring->filename); _dbus_string_free (&keyring->filename_lock); _dbus_string_free (&keyring->directory); free_keys (keyring->keys, keyring->n_keys); dbus_free (keyring); } } /** * Creates a new keyring that lives in the ~/.dbus-keyrings directory * of the user represented by @p credentials. If the @p credentials are * #NULL or empty, uses those of the current process. * * @param credentials a set of credentials representing a user or #NULL * @param context which keyring to get * @param error return location for errors * @returns the keyring or #NULL on error */ DBusKeyring* _dbus_keyring_new_for_credentials (DBusCredentials *credentials, const DBusString *context, DBusError *error) { DBusString ringdir; DBusKeyring *keyring; dbus_bool_t error_set; DBusError tmp_error; DBusCredentials *our_credentials; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_dbus_check_setuid ()) { dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, "Unable to create DBus keyring when setuid"); return NULL; } keyring = NULL; error_set = FALSE; our_credentials = NULL; if (!_dbus_string_init (&ringdir)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (credentials != NULL) { our_credentials = _dbus_credentials_copy (credentials); } else { our_credentials = _dbus_credentials_new_from_current_process (); } if (our_credentials == NULL) goto failed; if (_dbus_credentials_are_anonymous (our_credentials)) { if (!_dbus_credentials_add_from_current_process (our_credentials)) goto failed; } if (!_dbus_append_keyring_directory_for_credentials (&ringdir, our_credentials)) goto failed; keyring = _dbus_keyring_new (); if (keyring == NULL) goto failed; _dbus_assert (keyring->credentials == NULL); keyring->credentials = our_credentials; our_credentials = NULL; /* so we don't unref it again later */ /* should have been validated already, but paranoia check here */ if (!_dbus_keyring_validate_context (context)) { error_set = TRUE; dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid context in keyring creation"); goto failed; } /* Save keyring dir in the keyring object */ if (!_dbus_string_copy (&ringdir, 0, &keyring->directory, 0)) goto failed; /* Create keyring->filename based on keyring dir and context */ if (!_dbus_string_copy (&keyring->directory, 0, &keyring->filename, 0)) goto failed; if (!_dbus_concat_dir_and_file (&keyring->filename, context)) goto failed; /* Create lockfile name */ if (!_dbus_string_copy (&keyring->filename, 0, &keyring->filename_lock, 0)) goto failed; if (!_dbus_string_append (&keyring->filename_lock, ".lock")) goto failed; /* Reload keyring */ dbus_error_init (&tmp_error); if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error)) { _dbus_verbose ("didn't load an existing keyring: %s\n", tmp_error.message); dbus_error_free (&tmp_error); } /* We don't fail fatally if we can't create the directory, * but the keyring will probably always be empty * unless someone else manages to create it */ dbus_error_init (&tmp_error); if (!_dbus_create_directory (&keyring->directory, &tmp_error)) { _dbus_verbose ("Creating keyring directory: %s\n", tmp_error.message); dbus_error_free (&tmp_error); } _dbus_string_free (&ringdir); return keyring; failed: if (!error_set) dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL); if (our_credentials) _dbus_credentials_unref (our_credentials); if (keyring) _dbus_keyring_unref (keyring); _dbus_string_free (&ringdir); return NULL; } /** * Checks whether the context is a valid context. * Contexts that might cause confusion when used * in filenames are not allowed (contexts can't * start with a dot or contain dir separators). * * @todo this is the most inefficient implementation * imaginable. * * @param context the context * @returns #TRUE if valid */ dbus_bool_t _dbus_keyring_validate_context (const DBusString *context) { if (_dbus_string_get_length (context) == 0) { _dbus_verbose ("context is zero-length\n"); return FALSE; } if (!_dbus_string_validate_ascii (context, 0, _dbus_string_get_length (context))) { _dbus_verbose ("context not valid ascii\n"); return FALSE; } /* no directory separators */ if (_dbus_string_find (context, 0, "/", NULL)) { _dbus_verbose ("context contains a slash\n"); return FALSE; } if (_dbus_string_find (context, 0, "\\", NULL)) { _dbus_verbose ("context contains a backslash\n"); return FALSE; } /* prevent attempts to use dotfiles or ".." or ".lock" * all of which might allow some kind of attack */ if (_dbus_string_find (context, 0, ".", NULL)) { _dbus_verbose ("context contains a dot\n"); return FALSE; } /* no spaces/tabs, those are used for separators in the protocol */ if (_dbus_string_find_blank (context, 0, NULL)) { _dbus_verbose ("context contains a blank\n"); return FALSE; } if (_dbus_string_find (context, 0, "\n", NULL)) { _dbus_verbose ("context contains a newline\n"); return FALSE; } if (_dbus_string_find (context, 0, "\r", NULL)) { _dbus_verbose ("context contains a carriage return\n"); return FALSE; } return TRUE; } static DBusKey* find_recent_key (DBusKeyring *keyring) { int i; long tv_sec, tv_usec; _dbus_get_real_time (&tv_sec, &tv_usec); i = 0; while (i < keyring->n_keys) { DBusKey *key = &keyring->keys[i]; _dbus_verbose ("Key %d is %ld seconds old\n", i, tv_sec - key->creation_time); if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time) return key; ++i; } return NULL; } /** * Gets a recent key to use for authentication. * If no recent key exists, creates one. Returns * the key ID. If a key can't be written to the keyring * file so no recent key can be created, returns -1. * All valid keys are > 0. * * @param keyring the keyring * @param error error on failure * @returns key ID to use for auth, or -1 on failure */ int _dbus_keyring_get_best_key (DBusKeyring *keyring, DBusError *error) { DBusKey *key; _DBUS_ASSERT_ERROR_IS_CLEAR (error); key = find_recent_key (keyring); if (key) return key->id; /* All our keys are too old, or we've never loaded the * keyring. Create a new one. */ if (!_dbus_keyring_reload (keyring, TRUE, error)) return -1; key = find_recent_key (keyring); if (key) return key->id; else { dbus_set_error_const (error, DBUS_ERROR_FAILED, "No recent-enough key found in keyring, and unable to create a new key"); return -1; } } /** * Checks whether the keyring is for the same user as the given credentials. * * @param keyring the keyring * @param credentials the credentials to check * * @returns #TRUE if the keyring belongs to the given user */ dbus_bool_t _dbus_keyring_is_for_credentials (DBusKeyring *keyring, DBusCredentials *credentials) { return _dbus_credentials_same_user (keyring->credentials, credentials); } /** * Gets the hex-encoded secret key for the given ID. * Returns #FALSE if not enough memory. Returns #TRUE * but empty key on any other error such as unknown * key ID. * * @param keyring the keyring * @param key_id the key ID * @param hex_key string to append hex-encoded key to * @returns #TRUE if we had enough memory */ dbus_bool_t _dbus_keyring_get_hex_key (DBusKeyring *keyring, int key_id, DBusString *hex_key) { DBusKey *key; key = find_key_by_id (keyring->keys, keyring->n_keys, key_id); if (key == NULL) return TRUE; /* had enough memory, so TRUE */ return _dbus_string_hex_encode (&key->secret, 0, hex_key, _dbus_string_get_length (hex_key)); } /** @} */ /* end of exposed API */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include dbus_bool_t _dbus_keyring_test (void) { DBusString context; DBusKeyring *ring1; DBusKeyring *ring2; int id; DBusError error; int i; ring1 = NULL; ring2 = NULL; /* Context validation */ _dbus_string_init_const (&context, "foo"); _dbus_assert (_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "org_freedesktop_blah"); _dbus_assert (_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, ""); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, ".foo"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "bar.foo"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "bar/foo"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "bar\\foo"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "foo\xfa\xf0"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "foo\x80"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "foo\x7f"); _dbus_assert (_dbus_keyring_validate_context (&context)); _dbus_string_init_const (&context, "foo bar"); _dbus_assert (!_dbus_keyring_validate_context (&context)); if (!_dbus_string_init (&context)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_append_byte (&context, '\0')) _dbus_assert_not_reached ("no memory"); _dbus_assert (!_dbus_keyring_validate_context (&context)); _dbus_string_free (&context); /* Now verify that if we create a key in keyring 1, * it is properly loaded in keyring 2 */ _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite"); dbus_error_init (&error); ring1 = _dbus_keyring_new_for_credentials (NULL, &context, &error); _dbus_assert (ring1 != NULL); _dbus_assert (error.name == NULL); id = _dbus_keyring_get_best_key (ring1, &error); if (id < 0) { fprintf (stderr, "Could not load keyring: %s\n", error.message); dbus_error_free (&error); goto failure; } ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error); _dbus_assert (ring2 != NULL); _dbus_assert (error.name == NULL); if (ring1->n_keys != ring2->n_keys) { fprintf (stderr, "Different number of keys in keyrings\n"); goto failure; } /* We guarantee we load and save keeping keys in a fixed * order */ i = 0; while (i < ring1->n_keys) { if (ring1->keys[i].id != ring2->keys[i].id) { fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n", ring1->keys[i].id, ring2->keys[i].id); goto failure; } if (ring1->keys[i].creation_time != ring2->keys[i].creation_time) { fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n", ring1->keys[i].creation_time, ring2->keys[i].creation_time); goto failure; } if (!_dbus_string_equal (&ring1->keys[i].secret, &ring2->keys[i].secret)) { fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n"); goto failure; } ++i; } printf (" %d keys in test\n", ring1->n_keys); /* Test ref/unref */ _dbus_keyring_ref (ring1); _dbus_keyring_ref (ring2); _dbus_keyring_unref (ring1); _dbus_keyring_unref (ring2); /* really unref */ _dbus_keyring_unref (ring1); _dbus_keyring_unref (ring2); return TRUE; failure: if (ring1) _dbus_keyring_unref (ring1); if (ring2) _dbus_keyring_unref (ring2); return FALSE; } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ dbus-1.10.6/dbus/dbus-errors.c0000644000175000017500000002657712602773110016126 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-errors.c Error reporting * * Copyright (C) 2002, 2004 Red Hat Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-errors.h" #include "dbus-internals.h" #include "dbus-string.h" #include "dbus-protocol.h" #include #include /** * @defgroup DBusErrorInternals Error reporting internals * @ingroup DBusInternals * @brief Error reporting internals * @{ */ /** * @def DBUS_ERROR_INIT * * Expands to a suitable initializer for a DBusError on the stack. * Declaring a DBusError with: * * @code * DBusError error = DBUS_ERROR_INIT; * * do_things_with (&error); * @endcode * * is a more concise form of: * * @code * DBusError error; * * dbus_error_init (&error); * do_things_with (&error); * @endcode */ /** * Internals of DBusError */ typedef struct { char *name; /**< error name */ char *message; /**< error message */ unsigned int const_message : 1; /**< Message is not owned by DBusError */ unsigned int dummy2 : 1; /**< placeholder */ unsigned int dummy3 : 1; /**< placeholder */ unsigned int dummy4 : 1; /**< placeholder */ unsigned int dummy5 : 1; /**< placeholder */ void *padding1; /**< placeholder */ } DBusRealError; _DBUS_STATIC_ASSERT (sizeof (DBusRealError) == sizeof (DBusError)); /** * Returns a longer message describing an error name. * If the error name is unknown, returns the name * itself. * * @param error the error to describe * @returns a constant string describing the error. */ static const char* message_from_error (const char *error) { if (strcmp (error, DBUS_ERROR_FAILED) == 0) return "Unknown error"; else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0) return "Not enough memory available"; else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0) return "Error reading or writing data"; else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0) return "Could not parse address"; else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0) return "Feature not supported"; else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0) return "Resource limits exceeded"; else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0) return "Permission denied"; else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0) return "Could not authenticate to server"; else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0) return "No server available at address"; else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0) return "Connection timed out"; else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0) return "Network unavailable"; else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0) return "Address already in use"; else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0) return "Disconnected."; else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0) return "Invalid arguments."; else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0) return "Did not get a reply message."; else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0) return "File doesn't exist."; else if (strcmp (error, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) return "Object path already in use"; else return error; } /** @} */ /* End of internals */ /** * @defgroup DBusErrors Error reporting * @ingroup DBus * @brief Error reporting * * Types and functions related to reporting errors. * * * In essence D-Bus error reporting works as follows: * * @code * DBusError error; * dbus_error_init (&error); * dbus_some_function (arg1, arg2, &error); * if (dbus_error_is_set (&error)) * { * fprintf (stderr, "an error occurred: %s\n", error.message); * dbus_error_free (&error); * } * @endcode * * By convention, all functions allow #NULL instead of a DBusError*, * so callers who don't care about the error can ignore it. * * There are some rules. An error passed to a D-Bus function must * always be unset; you can't pass in an error that's already set. If * a function has a return code indicating whether an error occurred, * and also a #DBusError parameter, then the error will always be set * if and only if the return code indicates an error occurred. i.e. * the return code and the error are never going to disagree. * * An error only needs to be freed if it's been set, not if * it's merely been initialized. * * You can check the specific error that occurred using * dbus_error_has_name(). * * Errors will not be set for programming errors, such as passing * invalid arguments to the libdbus API. Instead, libdbus will print * warnings, exit on a failed assertion, or even crash in those cases * (in other words, incorrect use of the API results in undefined * behavior, possibly accompanied by helpful debugging output if * you're lucky). * * @{ */ /** * Initializes a DBusError structure. Does not allocate any memory; * the error only needs to be freed if it is set at some point. * * @param error the DBusError. */ void dbus_error_init (DBusError *error) { DBusRealError *real; _DBUS_STATIC_ASSERT (sizeof (DBusError) == sizeof (DBusRealError)); _dbus_return_if_fail (error != NULL); real = (DBusRealError *)error; real->name = NULL; real->message = NULL; real->const_message = TRUE; } /** * Frees an error that's been set (or just initialized), * then reinitializes the error as in dbus_error_init(). * * @param error memory where the error is stored. */ void dbus_error_free (DBusError *error) { DBusRealError *real; _dbus_return_if_fail (error != NULL); real = (DBusRealError *)error; if (!real->const_message) { dbus_free (real->name); dbus_free (real->message); } dbus_error_init (error); } /** * Assigns an error name and message to a DBusError. Does nothing if * error is #NULL. The message may be #NULL, which means a default * message will be deduced from the name. The default message will be * totally useless, though, so using a #NULL message is not recommended. * * Because this function does not copy the error name or message, you * must ensure the name and message are global data that won't be * freed. You probably want dbus_set_error() instead, in most cases. * * @param error the error or #NULL * @param name the error name (not copied!!!) * @param message the error message (not copied!!!) */ void dbus_set_error_const (DBusError *error, const char *name, const char *message) { DBusRealError *real; _dbus_return_if_error_is_set (error); _dbus_return_if_fail (name != NULL); if (error == NULL) return; _dbus_assert (error->name == NULL); _dbus_assert (error->message == NULL); if (message == NULL) message = message_from_error (name); real = (DBusRealError *)error; real->name = (char*) name; real->message = (char *)message; real->const_message = TRUE; } /** * Moves an error src into dest, freeing src and * overwriting dest. Both src and dest must be initialized. * src is reinitialized to an empty error. dest may not * contain an existing error. If the destination is * #NULL, just frees and reinits the source error. * * @param src the source error * @param dest the destination error or #NULL */ void dbus_move_error (DBusError *src, DBusError *dest) { _dbus_return_if_error_is_set (dest); if (dest) { dbus_error_free (dest); *dest = *src; dbus_error_init (src); } else dbus_error_free (src); } /** * Checks whether the error is set and has the given * name. * @param error the error * @param name the name * @returns #TRUE if the given named error occurred */ dbus_bool_t dbus_error_has_name (const DBusError *error, const char *name) { _dbus_return_val_if_fail (error != NULL, FALSE); _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_assert ((error->name != NULL && error->message != NULL) || (error->name == NULL && error->message == NULL)); if (error->name != NULL) { DBusString str1, str2; _dbus_string_init_const (&str1, error->name); _dbus_string_init_const (&str2, name); return _dbus_string_equal (&str1, &str2); } else return FALSE; } /** * Checks whether an error occurred (the error is set). * * @param error the error object * @returns #TRUE if an error occurred */ dbus_bool_t dbus_error_is_set (const DBusError *error) { _dbus_return_val_if_fail (error != NULL, FALSE); _dbus_assert ((error->name != NULL && error->message != NULL) || (error->name == NULL && error->message == NULL)); return error->name != NULL; } /** * Assigns an error name and message to a DBusError. * Does nothing if error is #NULL. * * The format may be #NULL, which means a (pretty much useless) * default message will be deduced from the name. This is not a good * idea, just go ahead and provide a useful error message. It won't * hurt you. * * If no memory can be allocated for the error message, * an out-of-memory error message will be set instead. * * @param error the error.or #NULL * @param name the error name * @param format printf-style format string. */ void dbus_set_error (DBusError *error, const char *name, const char *format, ...) { va_list args; if (error == NULL) return; /* it's a bug to pile up errors */ _dbus_return_if_error_is_set (error); _dbus_return_if_fail (name != NULL); va_start (args, format); _dbus_set_error_valist (error, name, format, args); va_end (args); } void _dbus_set_error_valist (DBusError *error, const char *name, const char *format, va_list args) { DBusRealError *real; DBusString str; _dbus_assert (name != NULL); if (error == NULL) return; _dbus_assert (error->name == NULL); _dbus_assert (error->message == NULL); if (!_dbus_string_init (&str)) goto nomem; if (format == NULL) { if (!_dbus_string_append (&str, message_from_error (name))) { _dbus_string_free (&str); goto nomem; } } else { if (!_dbus_string_append_printf_valist (&str, format, args)) { _dbus_string_free (&str); goto nomem; } } real = (DBusRealError *)error; if (!_dbus_string_steal_data (&str, &real->message)) { _dbus_string_free (&str); goto nomem; } _dbus_string_free (&str); real->name = _dbus_strdup (name); if (real->name == NULL) { dbus_free (real->message); real->message = NULL; goto nomem; } real->const_message = FALSE; return; nomem: _DBUS_SET_OOM (error); } /** @} */ /* End public API */ dbus-1.10.6/dbus/dbus-credentials.h0000644000175000017500000001233412602773110017076 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-credentials.h Credentials provable through authentication * * Copyright (C) 2007 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_CREDENTIALS_H #define DBUS_CREDENTIALS_H #include #include #include #include DBUS_BEGIN_DECLS typedef enum { DBUS_CREDENTIAL_UNIX_PROCESS_ID, DBUS_CREDENTIAL_UNIX_USER_ID, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, DBUS_CREDENTIAL_LINUX_SECURITY_LABEL, DBUS_CREDENTIAL_WINDOWS_SID } DBusCredentialType; DBUS_PRIVATE_EXPORT DBusCredentials* _dbus_credentials_new_from_current_process (void); DBUS_PRIVATE_EXPORT DBusCredentials* _dbus_credentials_new (void); DBUS_PRIVATE_EXPORT void _dbus_credentials_ref (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT void _dbus_credentials_unref (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_add_pid (DBusCredentials *credentials, dbus_pid_t pid); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials *credentials, dbus_uid_t uid); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, const char *windows_sid); dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials, const char *label); dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, void *audit_data, dbus_int32_t size); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_include (DBusCredentials *credentials, DBusCredentialType type); DBUS_PRIVATE_EXPORT dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials); const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials); void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials); dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials, DBusCredentials *possible_subset); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_are_empty (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_are_anonymous (DBusCredentials *credentials); dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials *credentials, DBusCredentials *other_credentials); /* must silently allow 'which' to not exist */ dbus_bool_t _dbus_credentials_add_credential (DBusCredentials *credentials, DBusCredentialType which, DBusCredentials *other_credentials); DBUS_PRIVATE_EXPORT void _dbus_credentials_clear (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT DBusCredentials* _dbus_credentials_copy (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_same_user (DBusCredentials *credentials, DBusCredentials *other_credentials); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_to_string_append (DBusCredentials *credentials, DBusString *string); DBUS_END_DECLS #endif /* DBUS_CREDENTIALS_H */ dbus-1.10.6/dbus/dbus-credentials.c0000644000175000017500000004215312602773110017073 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-credentials.c Credentials provable through authentication * * Copyright (C) 2007 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "dbus-credentials.h" #include "dbus-internals.h" /** * @defgroup DBusCredentials Credentials provable through authentication * @ingroup DBusInternals * @brief DBusCredentials object * * Credentials are what you have to prove you have in order to * authenticate. The main credentials right now are a unix user * account, a Windows user account, or a UNIX process ID. */ /** * @defgroup DBusCredentialsInternals Credentials implementation details * @ingroup DBusInternals * @brief DBusCredentials implementation details * * Private details of credentials code. * * @{ */ struct DBusCredentials { int refcount; dbus_uid_t unix_uid; dbus_pid_t pid; char *windows_sid; char *linux_security_label; void *adt_audit_data; dbus_int32_t adt_audit_data_size; }; /** @} */ /** * @addtogroup DBusCredentials * @{ */ /** * Creates a new credentials object. * * @returns the new object or #NULL if no memory */ DBusCredentials* _dbus_credentials_new (void) { DBusCredentials *creds; creds = dbus_new (DBusCredentials, 1); if (creds == NULL) return NULL; creds->refcount = 1; creds->unix_uid = DBUS_UID_UNSET; creds->pid = DBUS_PID_UNSET; creds->windows_sid = NULL; creds->linux_security_label = NULL; creds->adt_audit_data = NULL; creds->adt_audit_data_size = 0; return creds; } /** * Creates a new object with credentials (user ID and process ID) from the current process. * @returns the new object or #NULL if no memory */ DBusCredentials* _dbus_credentials_new_from_current_process (void) { DBusCredentials *creds; creds = _dbus_credentials_new (); if (creds == NULL) return NULL; if (!_dbus_credentials_add_from_current_process (creds)) { _dbus_credentials_unref (creds); return NULL; } return creds; } /** * Increment refcount on credentials. * * @param credentials the object */ void _dbus_credentials_ref (DBusCredentials *credentials) { _dbus_assert (credentials->refcount > 0); credentials->refcount += 1; } /** * Decrement refcount on credentials. * * @param credentials the object */ void _dbus_credentials_unref (DBusCredentials *credentials) { _dbus_assert (credentials->refcount > 0); credentials->refcount -= 1; if (credentials->refcount == 0) { dbus_free (credentials->windows_sid); dbus_free (credentials->linux_security_label); dbus_free (credentials->adt_audit_data); dbus_free (credentials); } } /** * Add a UNIX process ID to the credentials. * * @param credentials the object * @param pid the process ID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_pid (DBusCredentials *credentials, dbus_pid_t pid) { credentials->pid = pid; return TRUE; } /** * Add a UNIX user ID to the credentials. * * @param credentials the object * @param uid the user ID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_unix_uid(DBusCredentials *credentials, dbus_uid_t uid) { credentials->unix_uid = uid; return TRUE; } /** * Add a Windows user SID to the credentials. * * @param credentials the object * @param windows_sid the user SID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, const char *windows_sid) { char *copy; copy = _dbus_strdup (windows_sid); if (copy == NULL) return FALSE; dbus_free (credentials->windows_sid); credentials->windows_sid = copy; return TRUE; } /** * Add a Linux security label, as used by LSMs such as SELinux, Smack and * AppArmor, to the credentials. * * @param credentials the object * @param label the label * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials, const char *label) { char *copy; copy = _dbus_strdup (label); if (copy == NULL) return FALSE; dbus_free (credentials->linux_security_label); credentials->linux_security_label = copy; return TRUE; } /** * Add ADT audit data to the credentials. * * @param credentials the object * @param audit_data the audit data * @param size the length of audit data * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, void *audit_data, dbus_int32_t size) { void *copy; copy = _dbus_memdup (audit_data, size); if (copy == NULL) return FALSE; dbus_free (credentials->adt_audit_data); credentials->adt_audit_data = copy; credentials->adt_audit_data_size = size; return TRUE; } /** * Checks whether the given credential is present. * * @param credentials the object * @param type the credential to check for * @returns #TRUE if the credential is present */ dbus_bool_t _dbus_credentials_include (DBusCredentials *credentials, DBusCredentialType type) { switch (type) { case DBUS_CREDENTIAL_UNIX_PROCESS_ID: return credentials->pid != DBUS_PID_UNSET; case DBUS_CREDENTIAL_UNIX_USER_ID: return credentials->unix_uid != DBUS_UID_UNSET; case DBUS_CREDENTIAL_WINDOWS_SID: return credentials->windows_sid != NULL; case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL: return credentials->linux_security_label != NULL; case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID: return credentials->adt_audit_data != NULL; } _dbus_assert_not_reached ("Unknown credential enum value"); return FALSE; } /** * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if * the credentials object doesn't contain a process ID. * * @param credentials the object * @returns UNIX process ID */ dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials) { return credentials->pid; } /** * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if * the credentials object doesn't contain a user ID. * * @param credentials the object * @returns UNIX user ID */ dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials) { return credentials->unix_uid; } /** * Gets the Windows user SID in the credentials, or #NULL if * the credentials object doesn't contain a Windows user SID. * * @param credentials the object * @returns Windows user SID */ const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials) { return credentials->windows_sid; } /** * Gets the Linux security label (as used by LSMs) from the credentials, * or #NULL if the credentials object doesn't contain a security label. * * @param credentials the object * @returns the security label */ const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials) { return credentials->linux_security_label; } /** * Gets the ADT audit data in the credentials, or #NULL if * the credentials object doesn't contain ADT audit data. * * @param credentials the object * @returns Solaris ADT audit data */ void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials) { return credentials->adt_audit_data; } /** * Gets the ADT audit data size in the credentials, or 0 if * the credentials object doesn't contain ADT audit data. * * @param credentials the object * @returns Solaris ADT audit data size */ dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials) { return credentials->adt_audit_data_size; } /** * Checks whether the first credentials object contains * all the credentials found in the second credentials object. * * @param credentials the object * @param possible_subset see if credentials in here are also in the first arg * @returns #TRUE if second arg is contained in first */ dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials, DBusCredentials *possible_subset) { return (possible_subset->pid == DBUS_PID_UNSET || possible_subset->pid == credentials->pid) && (possible_subset->unix_uid == DBUS_UID_UNSET || possible_subset->unix_uid == credentials->unix_uid) && (possible_subset->windows_sid == NULL || (credentials->windows_sid && strcmp (possible_subset->windows_sid, credentials->windows_sid) == 0)) && (possible_subset->linux_security_label == NULL || (credentials->linux_security_label != NULL && strcmp (possible_subset->linux_security_label, credentials->linux_security_label) == 0)) && (possible_subset->adt_audit_data == NULL || (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data, credentials->adt_audit_data, credentials->adt_audit_data_size) == 0)); } /** * Checks whether a credentials object contains anything. * * @param credentials the object * @returns #TRUE if there are no credentials in the object */ dbus_bool_t _dbus_credentials_are_empty (DBusCredentials *credentials) { return credentials->pid == DBUS_PID_UNSET && credentials->unix_uid == DBUS_UID_UNSET && credentials->windows_sid == NULL && credentials->linux_security_label == NULL && credentials->adt_audit_data == NULL; } /** * Checks whether a credentials object contains a user identity. * * @param credentials the object * @returns #TRUE if there are no user identities in the object */ dbus_bool_t _dbus_credentials_are_anonymous (DBusCredentials *credentials) { return credentials->unix_uid == DBUS_UID_UNSET && credentials->windows_sid == NULL; } /** * Merge all credentials found in the second object into the first object, * overwriting the first object if there are any overlaps. * * @param credentials the object * @param other_credentials credentials to merge * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials *credentials, DBusCredentials *other_credentials) { return _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_UNIX_PROCESS_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_UNIX_USER_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_LINUX_SECURITY_LABEL, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_WINDOWS_SID, other_credentials); } /** * Merge the given credential found in the second object into the first object, * overwriting the first object's value for that credential. * * Does nothing if the second object does not contain the specified credential. * i.e., will never delete a credential from the first object. * * @param credentials the object * @param which the credential to overwrite * @param other_credentials credentials to merge * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_credential (DBusCredentials *credentials, DBusCredentialType which, DBusCredentials *other_credentials) { if (which == DBUS_CREDENTIAL_UNIX_PROCESS_ID && other_credentials->pid != DBUS_PID_UNSET) { if (!_dbus_credentials_add_pid (credentials, other_credentials->pid)) return FALSE; } else if (which == DBUS_CREDENTIAL_UNIX_USER_ID && other_credentials->unix_uid != DBUS_UID_UNSET) { if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) return FALSE; } else if (which == DBUS_CREDENTIAL_WINDOWS_SID && other_credentials->windows_sid != NULL) { if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid)) return FALSE; } else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL && other_credentials->linux_security_label != NULL) { if (!_dbus_credentials_add_linux_security_label (credentials, other_credentials->linux_security_label)) return FALSE; } else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID && other_credentials->adt_audit_data != NULL) { if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size)) return FALSE; } return TRUE; } /** * Clear all credentials in the object. * * @param credentials the object */ void _dbus_credentials_clear (DBusCredentials *credentials) { credentials->pid = DBUS_PID_UNSET; credentials->unix_uid = DBUS_UID_UNSET; dbus_free (credentials->windows_sid); credentials->windows_sid = NULL; dbus_free (credentials->linux_security_label); credentials->linux_security_label = NULL; dbus_free (credentials->adt_audit_data); credentials->adt_audit_data = NULL; credentials->adt_audit_data_size = 0; } /** * Copy a credentials object. * * @param credentials the object * @returns the copy or #NULL */ DBusCredentials* _dbus_credentials_copy (DBusCredentials *credentials) { DBusCredentials *copy; copy = _dbus_credentials_new (); if (copy == NULL) return NULL; if (!_dbus_credentials_add_credentials (copy, credentials)) { _dbus_credentials_unref (copy); return NULL; } return copy; } /** * Check whether the user-identifying credentials in two credentials * objects are identical. Credentials that are not related to the * user are ignored, but any kind of user ID credentials must be the * same (UNIX user ID, Windows user SID, etc.) and present in both * objects for the function to return #TRUE. * * @param credentials the object * @param other_credentials credentials to compare * @returns #TRUE if the two credentials refer to the same user */ dbus_bool_t _dbus_credentials_same_user (DBusCredentials *credentials, DBusCredentials *other_credentials) { /* both windows and unix user must be the same (though pretty much * in all conceivable cases, one will be unset) */ return credentials->unix_uid == other_credentials->unix_uid && ((!(credentials->windows_sid || other_credentials->windows_sid)) || (credentials->windows_sid && other_credentials->windows_sid && strcmp (credentials->windows_sid, other_credentials->windows_sid) == 0)); } /** * Convert the credentials in this object to a human-readable * string format, and append to the given string. * * @param credentials the object * @param string append to this string * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_to_string_append (DBusCredentials *credentials, DBusString *string) { dbus_bool_t join; join = FALSE; if (credentials->unix_uid != DBUS_UID_UNSET) { if (!_dbus_string_append_printf (string, "uid=" DBUS_UID_FORMAT, credentials->unix_uid)) goto oom; join = TRUE; } if (credentials->pid != DBUS_PID_UNSET) { if (!_dbus_string_append_printf (string, "%spid=" DBUS_PID_FORMAT, join ? " " : "", credentials->pid)) goto oom; join = TRUE; } else join = FALSE; if (credentials->windows_sid != NULL) { if (!_dbus_string_append_printf (string, "%ssid=%s", join ? " " : "", credentials->windows_sid)) goto oom; join = TRUE; } else join = FALSE; if (credentials->linux_security_label != NULL) { if (!_dbus_string_append_printf (string, "%slsm='%s'", join ? " " : "", credentials->linux_security_label)) goto oom; join = TRUE; } return TRUE; oom: return FALSE; } /** @} */ /* tests in dbus-credentials-util.c */ dbus-1.10.6/dbus/dbus-connection-internal.h0000644000175000017500000002103012602773110020543 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-connection-internal.h DBusConnection internal interfaces * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_CONNECTION_INTERNAL_H #define DBUS_CONNECTION_INTERNAL_H #include #include #include #include #include #include #include #include DBUS_BEGIN_DECLS typedef enum { DBUS_ITERATION_DO_WRITING = 1 << 0, /**< Write messages out. */ DBUS_ITERATION_DO_READING = 1 << 1, /**< Read messages in. */ DBUS_ITERATION_BLOCK = 1 << 2 /**< Block if nothing to do. */ } DBusIterationFlags; /** default timeout value when waiting for a message reply, 25 seconds */ #define _DBUS_DEFAULT_TIMEOUT_VALUE (25 * 1000) typedef void (* DBusPendingFdsChangeFunction) (void *data); DBUS_PRIVATE_EXPORT void _dbus_connection_lock (DBusConnection *connection); DBUS_PRIVATE_EXPORT void _dbus_connection_unlock (DBusConnection *connection); DBUS_PRIVATE_EXPORT DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection); DBUS_PRIVATE_EXPORT void _dbus_connection_unref_unlocked (DBusConnection *connection); void _dbus_connection_queue_received_message_link (DBusConnection *connection, DBusList *link); dbus_bool_t _dbus_connection_has_messages_to_send_unlocked (DBusConnection *connection); DBusMessage* _dbus_connection_get_message_to_send (DBusConnection *connection); void _dbus_connection_message_sent_unlocked (DBusConnection *connection, DBusMessage *message); dbus_bool_t _dbus_connection_add_watch_unlocked (DBusConnection *connection, DBusWatch *watch); void _dbus_connection_remove_watch_unlocked (DBusConnection *connection, DBusWatch *watch); void _dbus_connection_toggle_watch_unlocked (DBusConnection *connection, DBusWatch *watch, dbus_bool_t enabled); dbus_bool_t _dbus_connection_handle_watch (DBusWatch *watch, unsigned int condition, void *data); dbus_bool_t _dbus_connection_add_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout); void _dbus_connection_remove_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout); void _dbus_connection_toggle_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout, dbus_bool_t enabled); DBusConnection* _dbus_connection_new_for_transport (DBusTransport *transport); void _dbus_connection_do_iteration_unlocked (DBusConnection *connection, DBusPendingCall *pending, unsigned int flags, int timeout_milliseconds); void _dbus_connection_close_possibly_shared (DBusConnection *connection); void _dbus_connection_close_if_only_one_ref (DBusConnection *connection); DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler); void _dbus_pending_call_notify (DBusPendingCall *pending); void _dbus_connection_remove_pending_call (DBusConnection *connection, DBusPendingCall *pending); void _dbus_connection_block_pending_call (DBusPendingCall *pending); void _dbus_pending_call_complete_and_unlock (DBusPendingCall *pending, DBusMessage *message); dbus_bool_t _dbus_connection_send_and_unlock (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial); void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, DBusList *link); DBUS_PRIVATE_EXPORT void _dbus_connection_test_get_locks (DBusConnection *conn, DBusMutex **mutex_loc, DBusMutex **dispatch_mutex_loc, DBusMutex **io_path_mutex_loc, DBusCondVar **dispatch_cond_loc, DBusCondVar **io_path_cond_loc); DBUS_PRIVATE_EXPORT int _dbus_connection_get_pending_fds_count (DBusConnection *connection); DBUS_PRIVATE_EXPORT void _dbus_connection_set_pending_fds_function (DBusConnection *connection, DBusPendingFdsChangeFunction callback, void *data); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection, char **label_p); /* if DBUS_ENABLE_STATS */ DBUS_PRIVATE_EXPORT void _dbus_connection_get_stats (DBusConnection *connection, dbus_uint32_t *in_messages, dbus_uint32_t *in_bytes, dbus_uint32_t *in_fds, dbus_uint32_t *in_peak_bytes, dbus_uint32_t *in_peak_fds, dbus_uint32_t *out_messages, dbus_uint32_t *out_bytes, dbus_uint32_t *out_fds, dbus_uint32_t *out_peak_bytes, dbus_uint32_t *out_peak_fds); /* if DBUS_ENABLE_EMBEDDED_TESTS */ const char* _dbus_connection_get_address (DBusConnection *connection); /* This _dbus_bus_* stuff doesn't really belong here, but dbus-bus-internal.h seems * silly for one function */ /** * @addtogroup DBusBusInternals * @{ */ void _dbus_bus_notify_shared_connection_disconnected_unlocked (DBusConnection *connection); /** @} */ DBUS_END_DECLS #endif /* DBUS_CONNECTION_INTERNAL_H */ dbus-1.10.6/dbus/dbus-connection.c0000644000175000017500000065370512602773110016750 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-connection.c DBusConnection object * * Copyright (C) 2002-2006 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-shared.h" #include "dbus-connection.h" #include "dbus-list.h" #include "dbus-timeout.h" #include "dbus-transport.h" #include "dbus-watch.h" #include "dbus-connection-internal.h" #include "dbus-pending-call-internal.h" #include "dbus-list.h" #include "dbus-hash.h" #include "dbus-message-internal.h" #include "dbus-message-private.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-dataslot.h" #include "dbus-string.h" #include "dbus-signature.h" #include "dbus-pending-call.h" #include "dbus-object-tree.h" #include "dbus-threads-internal.h" #include "dbus-bus.h" #include "dbus-marshal-basic.h" #ifdef DBUS_DISABLE_CHECKS #define TOOK_LOCK_CHECK(connection) #define RELEASING_LOCK_CHECK(connection) #define HAVE_LOCK_CHECK(connection) #else #define TOOK_LOCK_CHECK(connection) do { \ _dbus_assert (!(connection)->have_connection_lock); \ (connection)->have_connection_lock = TRUE; \ } while (0) #define RELEASING_LOCK_CHECK(connection) do { \ _dbus_assert ((connection)->have_connection_lock); \ (connection)->have_connection_lock = FALSE; \ } while (0) #define HAVE_LOCK_CHECK(connection) _dbus_assert ((connection)->have_connection_lock) /* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ #endif #define TRACE_LOCKS 1 #define CONNECTION_LOCK(connection) do { \ if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \ _dbus_rmutex_lock ((connection)->mutex); \ TOOK_LOCK_CHECK (connection); \ } while (0) #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock (connection) #define SLOTS_LOCK(connection) do { \ _dbus_rmutex_lock ((connection)->slot_mutex); \ } while (0) #define SLOTS_UNLOCK(connection) do { \ _dbus_rmutex_unlock ((connection)->slot_mutex); \ } while (0) #define DISPATCH_STATUS_NAME(s) \ ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \ (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \ (s) == DBUS_DISPATCH_NEED_MEMORY ? "need memory" : \ "???") /** * @defgroup DBusConnection DBusConnection * @ingroup DBus * @brief Connection to another application * * A DBusConnection represents a connection to another * application. Messages can be sent and received via this connection. * The other application may be a message bus; for convenience, the * function dbus_bus_get() is provided to automatically open a * connection to the well-known message buses. * * In brief a DBusConnection is a message queue associated with some * message transport mechanism such as a socket. The connection * maintains a queue of incoming messages and a queue of outgoing * messages. * * Several functions use the following terms: *
      *
    • read means to fill the incoming message queue by reading from the socket
    • *
    • write means to drain the outgoing queue by writing to the socket
    • *
    • dispatch means to drain the incoming queue by invoking application-provided message handlers
    • *
    * * The function dbus_connection_read_write_dispatch() for example does all * three of these things, offering a simple alternative to a main loop. * * In an application with a main loop, the read/write/dispatch * operations are usually separate. * * The connection provides #DBusWatch and #DBusTimeout objects to * the main loop. These are used to know when reading, writing, or * dispatching should be performed. * * Incoming messages are processed * by calling dbus_connection_dispatch(). dbus_connection_dispatch() * runs any handlers registered for the topmost message in the message * queue, then discards the message, then returns. * * dbus_connection_get_dispatch_status() indicates whether * messages are currently in the queue that need dispatching. * dbus_connection_set_dispatch_status_function() allows * you to set a function to be used to monitor the dispatch status. * * If you're using GLib or Qt add-on libraries for D-Bus, there are * special convenience APIs in those libraries that hide * all the details of dispatch and watch/timeout monitoring. * For example, dbus_connection_setup_with_g_main(). * * If you aren't using these add-on libraries, but want to process * messages asynchronously, you must manually call * dbus_connection_set_dispatch_status_function(), * dbus_connection_set_watch_functions(), * dbus_connection_set_timeout_functions() providing appropriate * functions to integrate the connection with your application's main * loop. This can be tricky to get right; main loops are not simple. * * If you don't need to be asynchronous, you can ignore #DBusWatch, * #DBusTimeout, and dbus_connection_dispatch(). Instead, * dbus_connection_read_write_dispatch() can be used. * * Or, in very simple applications, * dbus_connection_pop_message() may be all you need, allowing you to * avoid setting up any handler functions (see * dbus_connection_add_filter(), * dbus_connection_register_object_path() for more on handlers). * * When you use dbus_connection_send() or one of its variants to send * a message, the message is added to the outgoing queue. It's * actually written to the network later; either in * dbus_watch_handle() invoked by your main loop, or in * dbus_connection_flush() which blocks until it can write out the * entire outgoing queue. The GLib/Qt add-on libraries again * handle the details here for you by setting up watch functions. * * When a connection is disconnected, you are guaranteed to get a * signal "Disconnected" from the interface * #DBUS_INTERFACE_LOCAL, path * #DBUS_PATH_LOCAL. * * You may not drop the last reference to a #DBusConnection * until that connection has been disconnected. * * You may dispatch the unprocessed incoming message queue even if the * connection is disconnected. However, "Disconnected" will always be * the last message in the queue (obviously no messages are received * after disconnection). * * After calling dbus_threads_init(), #DBusConnection has thread * locks and drops them when invoking user callbacks, so in general is * transparently threadsafe. However, #DBusMessage does NOT have * thread locks; you must not send the same message to multiple * #DBusConnection if those connections will be used from different threads, * for example. * * Also, if you dispatch or pop messages from multiple threads, it * may work in the sense that it won't crash, but it's tough to imagine * sane results; it will be completely unpredictable which messages * go to which threads. * * It's recommended to dispatch from a single thread. * * The most useful function to call from multiple threads at once * is dbus_connection_send_with_reply_and_block(). That is, * multiple threads can make method calls at the same time. * * If you aren't using threads, you can use a main loop and * dbus_pending_call_set_notify() to achieve a similar result. */ /** * @defgroup DBusConnectionInternals DBusConnection implementation details * @ingroup DBusInternals * @brief Implementation details of DBusConnection * * @{ */ static void _dbus_connection_trace_ref (DBusConnection *connection, int old_refcount, int new_refcount, const char *why) { #ifdef DBUS_ENABLE_VERBOSE_MODE static int enabled = -1; _dbus_trace_ref ("DBusConnection", connection, old_refcount, new_refcount, why, "DBUS_CONNECTION_TRACE", &enabled); #endif } /** * Internal struct representing a message filter function */ typedef struct DBusMessageFilter DBusMessageFilter; /** * Internal struct representing a message filter function */ struct DBusMessageFilter { DBusAtomic refcount; /**< Reference count */ DBusHandleMessageFunction function; /**< Function to call to filter */ void *user_data; /**< User data for the function */ DBusFreeFunction free_user_data_function; /**< Function to free the user data */ }; /** * Internals of DBusPreallocatedSend */ struct DBusPreallocatedSend { DBusConnection *connection; /**< Connection we'd send the message to */ DBusList *queue_link; /**< Preallocated link in the queue */ DBusList *counter_link; /**< Preallocated link in the resource counter */ }; #if HAVE_DECL_MSG_NOSIGNAL static dbus_bool_t _dbus_modify_sigpipe = FALSE; #else static dbus_bool_t _dbus_modify_sigpipe = TRUE; #endif /** * Implementation details of DBusConnection. All fields are private. */ struct DBusConnection { DBusAtomic refcount; /**< Reference count. */ DBusRMutex *mutex; /**< Lock on the entire DBusConnection */ DBusCMutex *dispatch_mutex; /**< Protects dispatch_acquired */ DBusCondVar *dispatch_cond; /**< Notify when dispatch_acquired is available */ DBusCMutex *io_path_mutex; /**< Protects io_path_acquired */ DBusCondVar *io_path_cond; /**< Notify when io_path_acquired is available */ DBusList *outgoing_messages; /**< Queue of messages we need to send, send the end of the list first. */ DBusList *incoming_messages; /**< Queue of messages we have received, end of the list received most recently. */ DBusList *expired_messages; /**< Messages that will be released when we next unlock. */ DBusMessage *message_borrowed; /**< Filled in if the first incoming message has been borrowed; * dispatch_acquired will be set by the borrower */ int n_outgoing; /**< Length of outgoing queue. */ int n_incoming; /**< Length of incoming queue. */ DBusCounter *outgoing_counter; /**< Counts size of outgoing messages. */ DBusTransport *transport; /**< Object that sends/receives messages over network. */ DBusWatchList *watches; /**< Stores active watches. */ DBusTimeoutList *timeouts; /**< Stores active timeouts. */ DBusList *filter_list; /**< List of filters. */ DBusRMutex *slot_mutex; /**< Lock on slot_list so overall connection lock need not be taken */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */ dbus_uint32_t client_serial; /**< Client serial. Increments each time a message is sent */ DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */ DBusWakeupMainFunction wakeup_main_function; /**< Function to wake up the mainloop */ void *wakeup_main_data; /**< Application data for wakeup_main_function */ DBusFreeFunction free_wakeup_main_data; /**< free wakeup_main_data */ DBusDispatchStatusFunction dispatch_status_function; /**< Function on dispatch status changes */ void *dispatch_status_data; /**< Application data for dispatch_status_function */ DBusFreeFunction free_dispatch_status_data; /**< free dispatch_status_data */ DBusDispatchStatus last_dispatch_status; /**< The last dispatch status we reported to the application. */ DBusObjectTree *objects; /**< Object path handlers registered with this connection */ char *server_guid; /**< GUID of server if we are in shared_connections, #NULL if server GUID is unknown or connection is private */ /* These two MUST be bools and not bitfields, because they are protected by a separate lock * from connection->mutex and all bitfields in a word have to be read/written together. * So you can't have a different lock for different bitfields in the same word. */ dbus_bool_t dispatch_acquired; /**< Someone has dispatch path (can drain incoming queue) */ dbus_bool_t io_path_acquired; /**< Someone has transport io path (can use the transport to read/write messages) */ unsigned int shareable : 1; /**< #TRUE if libdbus owns a reference to the connection and can return it from dbus_connection_open() more than once */ unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */ unsigned int route_peer_messages : 1; /**< If #TRUE, if org.freedesktop.DBus.Peer messages have a bus name, don't handle them automatically */ unsigned int disconnected_message_arrived : 1; /**< We popped or are dispatching the disconnected message. * if the disconnect_message_link is NULL then we queued it, but * this flag is whether it got to the head of the queue. */ unsigned int disconnected_message_processed : 1; /**< We did our default handling of the disconnected message, * such as closing the connection. */ #ifndef DBUS_DISABLE_CHECKS unsigned int have_connection_lock : 1; /**< Used to check locking */ #endif #if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT) int generation; /**< _dbus_current_generation that should correspond to this connection */ #endif }; static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection); static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, DBusDispatchStatus new_status); static void _dbus_connection_last_unref (DBusConnection *connection); static void _dbus_connection_acquire_dispatch (DBusConnection *connection); static void _dbus_connection_release_dispatch (DBusConnection *connection); static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection); static void _dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection); static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection); static dbus_bool_t _dbus_connection_peek_for_reply_unlocked (DBusConnection *connection, dbus_uint32_t client_serial); static DBusMessageFilter * _dbus_message_filter_ref (DBusMessageFilter *filter) { #ifdef DBUS_DISABLE_ASSERT _dbus_atomic_inc (&filter->refcount); #else dbus_int32_t old_value; old_value = _dbus_atomic_inc (&filter->refcount); _dbus_assert (old_value > 0); #endif return filter; } static void _dbus_message_filter_unref (DBusMessageFilter *filter) { dbus_int32_t old_value; old_value = _dbus_atomic_dec (&filter->refcount); _dbus_assert (old_value > 0); if (old_value == 1) { if (filter->free_user_data_function) (* filter->free_user_data_function) (filter->user_data); dbus_free (filter); } } /** * Acquires the connection lock. * * @param connection the connection. */ void _dbus_connection_lock (DBusConnection *connection) { CONNECTION_LOCK (connection); } /** * Releases the connection lock. * * @param connection the connection. */ void _dbus_connection_unlock (DBusConnection *connection) { DBusList *expired_messages; DBusList *iter; if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n"); } /* If we had messages that expired (fell off the incoming or outgoing * queues) while we were locked, actually release them now */ expired_messages = connection->expired_messages; connection->expired_messages = NULL; RELEASING_LOCK_CHECK (connection); _dbus_rmutex_unlock (connection->mutex); for (iter = _dbus_list_pop_first_link (&expired_messages); iter != NULL; iter = _dbus_list_pop_first_link (&expired_messages)) { DBusMessage *message = iter->data; dbus_message_unref (message); _dbus_list_free_link (iter); } } /** * Wakes up the main loop if it is sleeping * Needed if we're e.g. queueing outgoing messages * on a thread while the mainloop sleeps. * * @param connection the connection. */ static void _dbus_connection_wakeup_mainloop (DBusConnection *connection) { if (connection->wakeup_main_function) (*connection->wakeup_main_function) (connection->wakeup_main_data); } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Gets the locks so we can examine them * * @param connection the connection. * @param mutex_loc return for the location of the main mutex pointer * @param dispatch_mutex_loc return location of the dispatch mutex pointer * @param io_path_mutex_loc return location of the io_path mutex pointer * @param dispatch_cond_loc return location of the dispatch conditional * variable pointer * @param io_path_cond_loc return location of the io_path conditional * variable pointer */ void _dbus_connection_test_get_locks (DBusConnection *connection, DBusMutex **mutex_loc, DBusMutex **dispatch_mutex_loc, DBusMutex **io_path_mutex_loc, DBusCondVar **dispatch_cond_loc, DBusCondVar **io_path_cond_loc) { *mutex_loc = (DBusMutex *) connection->mutex; *dispatch_mutex_loc = (DBusMutex *) connection->dispatch_mutex; *io_path_mutex_loc = (DBusMutex *) connection->io_path_mutex; *dispatch_cond_loc = connection->dispatch_cond; *io_path_cond_loc = connection->io_path_cond; } #endif /** * Adds a message-containing list link to the incoming message queue, * taking ownership of the link and the message's current refcount. * Cannot fail due to lack of memory. * * @param connection the connection. * @param link the message link to queue. */ void _dbus_connection_queue_received_message_link (DBusConnection *connection, DBusList *link) { DBusPendingCall *pending; dbus_uint32_t reply_serial; DBusMessage *message; _dbus_assert (_dbus_transport_peek_is_authenticated (connection->transport)); _dbus_list_append_link (&connection->incoming_messages, link); message = link->data; /* If this is a reply we're waiting on, remove timeout for it */ reply_serial = dbus_message_get_reply_serial (message); if (reply_serial != 0) { pending = _dbus_hash_table_lookup_int (connection->pending_replies, reply_serial); if (pending != NULL) { if (_dbus_pending_call_is_timeout_added_unlocked (pending)) _dbus_connection_remove_timeout_unlocked (connection, _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); } } connection->n_incoming += 1; _dbus_connection_wakeup_mainloop (connection); _dbus_verbose ("Message %p (%s %s %s %s '%s' reply to %u) added to incoming queue %p, %d incoming\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message), dbus_message_get_reply_serial (message), connection, connection->n_incoming); _dbus_message_trace_ref (message, -1, -1, "_dbus_conection_queue_received_message_link"); } /** * Adds a link + message to the incoming message queue. * Can't fail. Takes ownership of both link and message. * * @param connection the connection. * @param link the list node and message to queue. * */ void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, DBusList *link) { HAVE_LOCK_CHECK (connection); _dbus_list_append_link (&connection->incoming_messages, link); connection->n_incoming += 1; _dbus_connection_wakeup_mainloop (connection); _dbus_message_trace_ref (link->data, -1, -1, "_dbus_connection_queue_synthesized_message_link"); _dbus_verbose ("Synthesized message %p added to incoming queue %p, %d incoming\n", link->data, connection, connection->n_incoming); } /** * Checks whether there are messages in the outgoing message queue. * Called with connection lock held. * * @param connection the connection. * @returns #TRUE if the outgoing queue is non-empty. */ dbus_bool_t _dbus_connection_has_messages_to_send_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); return connection->outgoing_messages != NULL; } /** * Checks whether there are messages in the outgoing message queue. * Use dbus_connection_flush() to block until all outgoing * messages have been written to the underlying transport * (such as a socket). * * @param connection the connection. * @returns #TRUE if the outgoing queue is non-empty. */ dbus_bool_t dbus_connection_has_messages_to_send (DBusConnection *connection) { dbus_bool_t v; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); v = _dbus_connection_has_messages_to_send_unlocked (connection); CONNECTION_UNLOCK (connection); return v; } /** * Gets the next outgoing message. The message remains in the * queue, and the caller does not own a reference to it. * * @param connection the connection. * @returns the message to be sent. */ DBusMessage* _dbus_connection_get_message_to_send (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); return _dbus_list_get_last (&connection->outgoing_messages); } /** * Notifies the connection that a message has been sent, so the * message can be removed from the outgoing queue. * Called with the connection lock held. * * @param connection the connection. * @param message the message that was sent. */ void _dbus_connection_message_sent_unlocked (DBusConnection *connection, DBusMessage *message) { DBusList *link; HAVE_LOCK_CHECK (connection); /* This can be called before we even complete authentication, since * it's called on disconnect to clean up the outgoing queue. * It's also called as we successfully send each message. */ link = _dbus_list_get_last_link (&connection->outgoing_messages); _dbus_assert (link != NULL); _dbus_assert (link->data == message); _dbus_list_unlink (&connection->outgoing_messages, link); _dbus_list_prepend_link (&connection->expired_messages, link); connection->n_outgoing -= 1; _dbus_verbose ("Message %p (%s %s %s %s '%s') removed from outgoing queue %p, %d left to send\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message), connection, connection->n_outgoing); /* It's OK that in principle we call the notify function, because for the * outgoing limit, there isn't one */ _dbus_message_remove_counter (message, connection->outgoing_counter); /* The message will actually be unreffed when we unlock */ } /** Function to be called in protected_change_watch() with refcount held */ typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, DBusWatch *watch); /** Function to be called in protected_change_watch() with refcount held */ typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, DBusWatch *watch); /** Function to be called in protected_change_watch() with refcount held */ typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, DBusWatch *watch, dbus_bool_t enabled); static dbus_bool_t protected_change_watch (DBusConnection *connection, DBusWatch *watch, DBusWatchAddFunction add_function, DBusWatchRemoveFunction remove_function, DBusWatchToggleFunction toggle_function, dbus_bool_t enabled) { dbus_bool_t retval; HAVE_LOCK_CHECK (connection); /* The original purpose of protected_change_watch() was to hold a * ref on the connection while dropping the connection lock, then * calling out to the app. This was a broken hack that did not * work, since the connection was in a hosed state (no WatchList * field) while calling out. * * So for now we'll just keep the lock while calling out. This means * apps are not allowed to call DBusConnection methods inside a * watch function or they will deadlock. * * The "real fix" is to use the _and_unlock() pattern found * elsewhere in the code, to defer calling out to the app until * we're about to drop locks and return flow of control to the app * anyway. * * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 */ if (connection->watches) { if (add_function) retval = (* add_function) (connection->watches, watch); else if (remove_function) { retval = TRUE; (* remove_function) (connection->watches, watch); } else { retval = TRUE; (* toggle_function) (connection->watches, watch, enabled); } return retval; } else return FALSE; } /** * Adds a watch using the connection's DBusAddWatchFunction if * available. Otherwise records the watch to be added when said * function is available. Also re-adds the watch if the * DBusAddWatchFunction changes. May fail due to lack of memory. * Connection lock should be held when calling this. * * @param connection the connection. * @param watch the watch to add. * @returns #TRUE on success. */ dbus_bool_t _dbus_connection_add_watch_unlocked (DBusConnection *connection, DBusWatch *watch) { return protected_change_watch (connection, watch, _dbus_watch_list_add_watch, NULL, NULL, FALSE); } /** * Removes a watch using the connection's DBusRemoveWatchFunction * if available. It's an error to call this function on a watch * that was not previously added. * Connection lock should be held when calling this. * * @param connection the connection. * @param watch the watch to remove. */ void _dbus_connection_remove_watch_unlocked (DBusConnection *connection, DBusWatch *watch) { protected_change_watch (connection, watch, NULL, _dbus_watch_list_remove_watch, NULL, FALSE); } /** * Toggles a watch and notifies app via connection's * DBusWatchToggledFunction if available. It's an error to call this * function on a watch that was not previously added. * Connection lock should be held when calling this. * * @param connection the connection. * @param watch the watch to toggle. * @param enabled whether to enable or disable */ void _dbus_connection_toggle_watch_unlocked (DBusConnection *connection, DBusWatch *watch, dbus_bool_t enabled) { _dbus_assert (watch != NULL); protected_change_watch (connection, watch, NULL, NULL, _dbus_watch_list_toggle_watch, enabled); } /** Function to be called in protected_change_timeout() with refcount held */ typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, DBusTimeout *timeout); /** Function to be called in protected_change_timeout() with refcount held */ typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, DBusTimeout *timeout); /** Function to be called in protected_change_timeout() with refcount held */ typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, DBusTimeout *timeout, dbus_bool_t enabled); static dbus_bool_t protected_change_timeout (DBusConnection *connection, DBusTimeout *timeout, DBusTimeoutAddFunction add_function, DBusTimeoutRemoveFunction remove_function, DBusTimeoutToggleFunction toggle_function, dbus_bool_t enabled) { dbus_bool_t retval; HAVE_LOCK_CHECK (connection); /* The original purpose of protected_change_timeout() was to hold a * ref on the connection while dropping the connection lock, then * calling out to the app. This was a broken hack that did not * work, since the connection was in a hosed state (no TimeoutList * field) while calling out. * * So for now we'll just keep the lock while calling out. This means * apps are not allowed to call DBusConnection methods inside a * timeout function or they will deadlock. * * The "real fix" is to use the _and_unlock() pattern found * elsewhere in the code, to defer calling out to the app until * we're about to drop locks and return flow of control to the app * anyway. * * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 */ if (connection->timeouts) { if (add_function) retval = (* add_function) (connection->timeouts, timeout); else if (remove_function) { retval = TRUE; (* remove_function) (connection->timeouts, timeout); } else { retval = TRUE; (* toggle_function) (connection->timeouts, timeout, enabled); } return retval; } else return FALSE; } /** * Adds a timeout using the connection's DBusAddTimeoutFunction if * available. Otherwise records the timeout to be added when said * function is available. Also re-adds the timeout if the * DBusAddTimeoutFunction changes. May fail due to lack of memory. * The timeout will fire repeatedly until removed. * Connection lock should be held when calling this. * * @param connection the connection. * @param timeout the timeout to add. * @returns #TRUE on success. */ dbus_bool_t _dbus_connection_add_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout) { return protected_change_timeout (connection, timeout, _dbus_timeout_list_add_timeout, NULL, NULL, FALSE); } /** * Removes a timeout using the connection's DBusRemoveTimeoutFunction * if available. It's an error to call this function on a timeout * that was not previously added. * Connection lock should be held when calling this. * * @param connection the connection. * @param timeout the timeout to remove. */ void _dbus_connection_remove_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout) { protected_change_timeout (connection, timeout, NULL, _dbus_timeout_list_remove_timeout, NULL, FALSE); } /** * Toggles a timeout and notifies app via connection's * DBusTimeoutToggledFunction if available. It's an error to call this * function on a timeout that was not previously added. * Connection lock should be held when calling this. * * @param connection the connection. * @param timeout the timeout to toggle. * @param enabled whether to enable or disable */ void _dbus_connection_toggle_timeout_unlocked (DBusConnection *connection, DBusTimeout *timeout, dbus_bool_t enabled) { protected_change_timeout (connection, timeout, NULL, NULL, _dbus_timeout_list_toggle_timeout, enabled); } static dbus_bool_t _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, DBusPendingCall *pending) { dbus_uint32_t reply_serial; DBusTimeout *timeout; HAVE_LOCK_CHECK (connection); reply_serial = _dbus_pending_call_get_reply_serial_unlocked (pending); _dbus_assert (reply_serial != 0); timeout = _dbus_pending_call_get_timeout_unlocked (pending); if (timeout) { if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) return FALSE; if (!_dbus_hash_table_insert_int (connection->pending_replies, reply_serial, pending)) { _dbus_connection_remove_timeout_unlocked (connection, timeout); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); HAVE_LOCK_CHECK (connection); return FALSE; } _dbus_pending_call_set_timeout_added_unlocked (pending, TRUE); } else { if (!_dbus_hash_table_insert_int (connection->pending_replies, reply_serial, pending)) { HAVE_LOCK_CHECK (connection); return FALSE; } } _dbus_pending_call_ref_unlocked (pending); HAVE_LOCK_CHECK (connection); return TRUE; } static void free_pending_call_on_hash_removal (void *data) { DBusPendingCall *pending; DBusConnection *connection; if (data == NULL) return; pending = data; connection = _dbus_pending_call_get_connection_unlocked (pending); HAVE_LOCK_CHECK (connection); if (_dbus_pending_call_is_timeout_added_unlocked (pending)) { _dbus_connection_remove_timeout_unlocked (connection, _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); } /* FIXME 1.0? this is sort of dangerous and undesirable to drop the lock * here, but the pending call finalizer could in principle call out to * application code so we pretty much have to... some larger code reorg * might be needed. */ _dbus_connection_ref_unlocked (connection); _dbus_pending_call_unref_and_unlock (pending); CONNECTION_LOCK (connection); _dbus_connection_unref_unlocked (connection); } static void _dbus_connection_detach_pending_call_unlocked (DBusConnection *connection, DBusPendingCall *pending) { /* This ends up unlocking to call the pending call finalizer, which is unexpected to * say the least. */ _dbus_hash_table_remove_int (connection->pending_replies, _dbus_pending_call_get_reply_serial_unlocked (pending)); } static void _dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, DBusPendingCall *pending) { /* The idea here is to avoid finalizing the pending call * with the lock held, since there's a destroy notifier * in pending call that goes out to application code. * * There's an extra unlock inside the hash table * "free pending call" function FIXME... */ _dbus_pending_call_ref_unlocked (pending); _dbus_hash_table_remove_int (connection->pending_replies, _dbus_pending_call_get_reply_serial_unlocked (pending)); if (_dbus_pending_call_is_timeout_added_unlocked (pending)) _dbus_connection_remove_timeout_unlocked (connection, _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); _dbus_pending_call_unref_and_unlock (pending); } /** * Removes a pending call from the connection, such that * the pending reply will be ignored. May drop the last * reference to the pending call. * * @param connection the connection * @param pending the pending call */ void _dbus_connection_remove_pending_call (DBusConnection *connection, DBusPendingCall *pending) { CONNECTION_LOCK (connection); _dbus_connection_detach_pending_call_and_unlock (connection, pending); } /** * Acquire the transporter I/O path. This must be done before * doing any I/O in the transporter. May sleep and drop the * IO path mutex while waiting for the I/O path. * * @param connection the connection. * @param timeout_milliseconds maximum blocking time, or -1 for no limit. * @returns TRUE if the I/O path was acquired. */ static dbus_bool_t _dbus_connection_acquire_io_path (DBusConnection *connection, int timeout_milliseconds) { dbus_bool_t we_acquired; HAVE_LOCK_CHECK (connection); /* We don't want the connection to vanish */ _dbus_connection_ref_unlocked (connection); /* We will only touch io_path_acquired which is protected by our mutex */ CONNECTION_UNLOCK (connection); _dbus_verbose ("locking io_path_mutex\n"); _dbus_cmutex_lock (connection->io_path_mutex); _dbus_verbose ("start connection->io_path_acquired = %d timeout = %d\n", connection->io_path_acquired, timeout_milliseconds); we_acquired = FALSE; if (connection->io_path_acquired) { if (timeout_milliseconds != -1) { _dbus_verbose ("waiting %d for IO path to be acquirable\n", timeout_milliseconds); if (!_dbus_condvar_wait_timeout (connection->io_path_cond, connection->io_path_mutex, timeout_milliseconds)) { /* We timed out before anyone signaled. */ /* (writing the loop to handle the !timedout case by * waiting longer if needed is a pain since dbus * wraps pthread_cond_timedwait to take a relative * time instead of absolute, something kind of stupid * on our part. for now it doesn't matter, we will just * end up back here eventually.) */ } } else { while (connection->io_path_acquired) { _dbus_verbose ("waiting for IO path to be acquirable\n"); _dbus_condvar_wait (connection->io_path_cond, connection->io_path_mutex); } } } if (!connection->io_path_acquired) { we_acquired = TRUE; connection->io_path_acquired = TRUE; } _dbus_verbose ("end connection->io_path_acquired = %d we_acquired = %d\n", connection->io_path_acquired, we_acquired); _dbus_verbose ("unlocking io_path_mutex\n"); _dbus_cmutex_unlock (connection->io_path_mutex); CONNECTION_LOCK (connection); HAVE_LOCK_CHECK (connection); _dbus_connection_unref_unlocked (connection); return we_acquired; } /** * Release the I/O path when you're done with it. Only call * after you've acquired the I/O. Wakes up at most one thread * currently waiting to acquire the I/O path. * * @param connection the connection. */ static void _dbus_connection_release_io_path (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); _dbus_verbose ("locking io_path_mutex\n"); _dbus_cmutex_lock (connection->io_path_mutex); _dbus_assert (connection->io_path_acquired); _dbus_verbose ("start connection->io_path_acquired = %d\n", connection->io_path_acquired); connection->io_path_acquired = FALSE; _dbus_condvar_wake_one (connection->io_path_cond); _dbus_verbose ("unlocking io_path_mutex\n"); _dbus_cmutex_unlock (connection->io_path_mutex); } /** * Queues incoming messages and sends outgoing messages for this * connection, optionally blocking in the process. Each call to * _dbus_connection_do_iteration_unlocked() will call select() or poll() one * time and then read or write data if possible. * * The purpose of this function is to be able to flush outgoing * messages or queue up incoming messages without returning * control to the application and causing reentrancy weirdness. * * The flags parameter allows you to specify whether to * read incoming messages, write outgoing messages, or both, * and whether to block if no immediate action is possible. * * The timeout_milliseconds parameter does nothing unless the * iteration is blocking. * * If there are no outgoing messages and DBUS_ITERATION_DO_READING * wasn't specified, then it's impossible to block, even if * you specify DBUS_ITERATION_BLOCK; in that case the function * returns immediately. * * If pending is not NULL then a check is made if the pending call * is completed after the io path has been required. If the call * has been completed nothing is done. This must be done since * the _dbus_connection_acquire_io_path releases the connection * lock for a while. * * Called with connection lock held. * * @param connection the connection. * @param pending the pending call that should be checked or NULL * @param flags iteration flags. * @param timeout_milliseconds maximum blocking time, or -1 for no limit. */ void _dbus_connection_do_iteration_unlocked (DBusConnection *connection, DBusPendingCall *pending, unsigned int flags, int timeout_milliseconds) { _dbus_verbose ("start\n"); HAVE_LOCK_CHECK (connection); if (connection->n_outgoing == 0) flags &= ~DBUS_ITERATION_DO_WRITING; if (_dbus_connection_acquire_io_path (connection, (flags & DBUS_ITERATION_BLOCK) ? timeout_milliseconds : 0)) { HAVE_LOCK_CHECK (connection); if ( (pending != NULL) && _dbus_pending_call_get_completed_unlocked(pending)) { _dbus_verbose ("pending call completed while acquiring I/O path"); } else if ( (pending != NULL) && _dbus_connection_peek_for_reply_unlocked (connection, _dbus_pending_call_get_reply_serial_unlocked (pending))) { _dbus_verbose ("pending call completed while acquiring I/O path (reply found in queue)"); } else { _dbus_transport_do_iteration (connection->transport, flags, timeout_milliseconds); } _dbus_connection_release_io_path (connection); } HAVE_LOCK_CHECK (connection); _dbus_verbose ("end\n"); } /** * Creates a new connection for the given transport. A transport * represents a message stream that uses some concrete mechanism, such * as UNIX domain sockets. May return #NULL if insufficient * memory exists to create the connection. * * @param transport the transport. * @returns the new connection, or #NULL on failure. */ DBusConnection* _dbus_connection_new_for_transport (DBusTransport *transport) { DBusConnection *connection; DBusWatchList *watch_list; DBusTimeoutList *timeout_list; DBusHashTable *pending_replies; DBusList *disconnect_link; DBusMessage *disconnect_message; DBusCounter *outgoing_counter; DBusObjectTree *objects; watch_list = NULL; connection = NULL; pending_replies = NULL; timeout_list = NULL; disconnect_link = NULL; disconnect_message = NULL; outgoing_counter = NULL; objects = NULL; watch_list = _dbus_watch_list_new (); if (watch_list == NULL) goto error; timeout_list = _dbus_timeout_list_new (); if (timeout_list == NULL) goto error; pending_replies = _dbus_hash_table_new (DBUS_HASH_INT, NULL, (DBusFreeFunction)free_pending_call_on_hash_removal); if (pending_replies == NULL) goto error; connection = dbus_new0 (DBusConnection, 1); if (connection == NULL) goto error; _dbus_rmutex_new_at_location (&connection->mutex); if (connection->mutex == NULL) goto error; _dbus_cmutex_new_at_location (&connection->io_path_mutex); if (connection->io_path_mutex == NULL) goto error; _dbus_cmutex_new_at_location (&connection->dispatch_mutex); if (connection->dispatch_mutex == NULL) goto error; _dbus_condvar_new_at_location (&connection->dispatch_cond); if (connection->dispatch_cond == NULL) goto error; _dbus_condvar_new_at_location (&connection->io_path_cond); if (connection->io_path_cond == NULL) goto error; _dbus_rmutex_new_at_location (&connection->slot_mutex); if (connection->slot_mutex == NULL) goto error; disconnect_message = dbus_message_new_signal (DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, "Disconnected"); if (disconnect_message == NULL) goto error; disconnect_link = _dbus_list_alloc_link (disconnect_message); if (disconnect_link == NULL) goto error; outgoing_counter = _dbus_counter_new (); if (outgoing_counter == NULL) goto error; objects = _dbus_object_tree_new (connection); if (objects == NULL) goto error; if (_dbus_modify_sigpipe) _dbus_disable_sigpipe (); /* initialized to 0: use atomic op to avoid mixing atomic and non-atomic */ _dbus_atomic_inc (&connection->refcount); connection->transport = transport; connection->watches = watch_list; connection->timeouts = timeout_list; connection->pending_replies = pending_replies; connection->outgoing_counter = outgoing_counter; connection->filter_list = NULL; connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */ connection->objects = objects; connection->exit_on_disconnect = FALSE; connection->shareable = FALSE; connection->route_peer_messages = FALSE; connection->disconnected_message_arrived = FALSE; connection->disconnected_message_processed = FALSE; #if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT) connection->generation = _dbus_current_generation; #endif _dbus_data_slot_list_init (&connection->slot_list); connection->client_serial = 1; connection->disconnect_message_link = disconnect_link; CONNECTION_LOCK (connection); if (!_dbus_transport_set_connection (transport, connection)) { CONNECTION_UNLOCK (connection); goto error; } _dbus_transport_ref (transport); CONNECTION_UNLOCK (connection); _dbus_connection_trace_ref (connection, 0, 1, "new_for_transport"); return connection; error: if (disconnect_message != NULL) dbus_message_unref (disconnect_message); if (disconnect_link != NULL) _dbus_list_free_link (disconnect_link); if (connection != NULL) { _dbus_condvar_free_at_location (&connection->io_path_cond); _dbus_condvar_free_at_location (&connection->dispatch_cond); _dbus_rmutex_free_at_location (&connection->mutex); _dbus_cmutex_free_at_location (&connection->io_path_mutex); _dbus_cmutex_free_at_location (&connection->dispatch_mutex); _dbus_rmutex_free_at_location (&connection->slot_mutex); dbus_free (connection); } if (pending_replies) _dbus_hash_table_unref (pending_replies); if (watch_list) _dbus_watch_list_free (watch_list); if (timeout_list) _dbus_timeout_list_free (timeout_list); if (outgoing_counter) _dbus_counter_unref (outgoing_counter); if (objects) _dbus_object_tree_unref (objects); return NULL; } /** * Increments the reference count of a DBusConnection. * Requires that the caller already holds the connection lock. * * @param connection the connection. * @returns the connection. */ DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection) { dbus_int32_t old_refcount; _dbus_assert (connection != NULL); _dbus_assert (connection->generation == _dbus_current_generation); HAVE_LOCK_CHECK (connection); old_refcount = _dbus_atomic_inc (&connection->refcount); _dbus_connection_trace_ref (connection, old_refcount, old_refcount + 1, "ref_unlocked"); return connection; } /** * Decrements the reference count of a DBusConnection. * Requires that the caller already holds the connection lock. * * @param connection the connection. */ void _dbus_connection_unref_unlocked (DBusConnection *connection) { dbus_int32_t old_refcount; HAVE_LOCK_CHECK (connection); _dbus_assert (connection != NULL); old_refcount = _dbus_atomic_dec (&connection->refcount); _dbus_connection_trace_ref (connection, old_refcount, old_refcount - 1, "unref_unlocked"); if (old_refcount == 1) _dbus_connection_last_unref (connection); } static dbus_uint32_t _dbus_connection_get_next_client_serial (DBusConnection *connection) { dbus_uint32_t serial; serial = connection->client_serial++; if (connection->client_serial == 0) connection->client_serial = 1; return serial; } /** * A callback for use with dbus_watch_new() to create a DBusWatch. * * @todo This is basically a hack - we could delete _dbus_transport_handle_watch() * and the virtual handle_watch in DBusTransport if we got rid of it. * The reason this is some work is threading, see the _dbus_connection_handle_watch() * implementation. * * @param watch the watch. * @param condition the current condition of the file descriptors being watched. * @param data must be a pointer to a #DBusConnection * @returns #FALSE if the IO condition may not have been fully handled due to lack of memory */ dbus_bool_t _dbus_connection_handle_watch (DBusWatch *watch, unsigned int condition, void *data) { DBusConnection *connection; dbus_bool_t retval; DBusDispatchStatus status; connection = data; _dbus_verbose ("start\n"); CONNECTION_LOCK (connection); if (!_dbus_connection_acquire_io_path (connection, 1)) { /* another thread is handling the message */ CONNECTION_UNLOCK (connection); return TRUE; } HAVE_LOCK_CHECK (connection); retval = _dbus_transport_handle_watch (connection->transport, watch, condition); _dbus_connection_release_io_path (connection); HAVE_LOCK_CHECK (connection); _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); _dbus_verbose ("end\n"); return retval; } /* Protected by _DBUS_LOCK (shared_connections) */ static DBusHashTable *shared_connections = NULL; static DBusList *shared_connections_no_guid = NULL; static void close_connection_on_shutdown (DBusConnection *connection) { DBusMessage *message; dbus_connection_ref (connection); _dbus_connection_close_possibly_shared (connection); /* Churn through to the Disconnected message */ while ((message = dbus_connection_pop_message (connection))) { dbus_message_unref (message); } dbus_connection_unref (connection); } static void shared_connections_shutdown (void *data) { int n_entries; if (!_DBUS_LOCK (shared_connections)) { /* We'd have initialized locks before adding anything, so there * can't be anything there. */ return; } /* This is a little bit unpleasant... better ideas? */ while ((n_entries = _dbus_hash_table_get_n_entries (shared_connections)) > 0) { DBusConnection *connection; DBusHashIter iter; _dbus_hash_iter_init (shared_connections, &iter); _dbus_hash_iter_next (&iter); connection = _dbus_hash_iter_get_value (&iter); _DBUS_UNLOCK (shared_connections); close_connection_on_shutdown (connection); if (!_DBUS_LOCK (shared_connections)) _dbus_assert_not_reached ("global locks were already initialized"); /* The connection should now be dead and not in our hash ... */ _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) < n_entries); } _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) == 0); _dbus_hash_table_unref (shared_connections); shared_connections = NULL; if (shared_connections_no_guid != NULL) { DBusConnection *connection; connection = _dbus_list_pop_first (&shared_connections_no_guid); while (connection != NULL) { _DBUS_UNLOCK (shared_connections); close_connection_on_shutdown (connection); if (!_DBUS_LOCK (shared_connections)) _dbus_assert_not_reached ("global locks were already initialized"); connection = _dbus_list_pop_first (&shared_connections_no_guid); } } shared_connections_no_guid = NULL; _DBUS_UNLOCK (shared_connections); } static dbus_bool_t connection_lookup_shared (DBusAddressEntry *entry, DBusConnection **result) { _dbus_verbose ("checking for existing connection\n"); *result = NULL; if (!_DBUS_LOCK (shared_connections)) { /* If it was shared, we'd have initialized global locks when we put * it in shared_connections. */ return FALSE; } if (shared_connections == NULL) { _dbus_verbose ("creating shared_connections hash table\n"); shared_connections = _dbus_hash_table_new (DBUS_HASH_STRING, dbus_free, NULL); if (shared_connections == NULL) { _DBUS_UNLOCK (shared_connections); return FALSE; } if (!_dbus_register_shutdown_func (shared_connections_shutdown, NULL)) { _dbus_hash_table_unref (shared_connections); shared_connections = NULL; _DBUS_UNLOCK (shared_connections); return FALSE; } _dbus_verbose (" successfully created shared_connections\n"); _DBUS_UNLOCK (shared_connections); return TRUE; /* no point looking up in the hash we just made */ } else { const char *guid; guid = dbus_address_entry_get_value (entry, "guid"); if (guid != NULL) { DBusConnection *connection; connection = _dbus_hash_table_lookup_string (shared_connections, guid); if (connection) { /* The DBusConnection can't be finalized without taking * the shared_connections lock to remove it from the * hash. So it's safe to ref the connection here. * However, it may be disconnected if the Disconnected * message hasn't been processed yet, in which case we * want to pretend it isn't in the hash and avoid * returning it. * * The idea is to avoid ever returning a disconnected connection * from dbus_connection_open(). We could just synchronously * drop our shared ref to the connection on connection disconnect, * and then assert here that the connection is connected, but * that causes reentrancy headaches. */ CONNECTION_LOCK (connection); if (_dbus_connection_get_is_connected_unlocked (connection)) { _dbus_connection_ref_unlocked (connection); *result = connection; _dbus_verbose ("looked up existing connection to server guid %s\n", guid); } else { _dbus_verbose ("looked up existing connection to server guid %s but it was disconnected so ignoring it\n", guid); } CONNECTION_UNLOCK (connection); } } _DBUS_UNLOCK (shared_connections); return TRUE; } } static dbus_bool_t connection_record_shared_unlocked (DBusConnection *connection, const char *guid) { char *guid_key; char *guid_in_connection; HAVE_LOCK_CHECK (connection); _dbus_assert (connection->server_guid == NULL); _dbus_assert (connection->shareable); /* get a hard ref on this connection, even if * we won't in fact store it in the hash, we still * need to hold a ref on it until it's disconnected. */ _dbus_connection_ref_unlocked (connection); if (guid == NULL) { if (!_DBUS_LOCK (shared_connections)) return FALSE; if (!_dbus_list_prepend (&shared_connections_no_guid, connection)) { _DBUS_UNLOCK (shared_connections); return FALSE; } _DBUS_UNLOCK (shared_connections); return TRUE; /* don't store in the hash */ } /* A separate copy of the key is required in the hash table, because * we don't have a lock on the connection when we are doing a hash * lookup. */ guid_key = _dbus_strdup (guid); if (guid_key == NULL) return FALSE; guid_in_connection = _dbus_strdup (guid); if (guid_in_connection == NULL) { dbus_free (guid_key); return FALSE; } if (!_DBUS_LOCK (shared_connections)) { dbus_free (guid_in_connection); dbus_free (guid_key); return FALSE; } _dbus_assert (shared_connections != NULL); if (!_dbus_hash_table_insert_string (shared_connections, guid_key, connection)) { dbus_free (guid_key); dbus_free (guid_in_connection); _DBUS_UNLOCK (shared_connections); return FALSE; } connection->server_guid = guid_in_connection; _dbus_verbose ("stored connection to %s to be shared\n", connection->server_guid); _DBUS_UNLOCK (shared_connections); _dbus_assert (connection->server_guid != NULL); return TRUE; } static void connection_forget_shared_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); if (!connection->shareable) return; if (!_DBUS_LOCK (shared_connections)) { /* If it was shared, we'd have initialized global locks when we put * it in the table; so it can't be there. */ return; } if (connection->server_guid != NULL) { _dbus_verbose ("dropping connection to %s out of the shared table\n", connection->server_guid); if (!_dbus_hash_table_remove_string (shared_connections, connection->server_guid)) _dbus_assert_not_reached ("connection was not in the shared table"); dbus_free (connection->server_guid); connection->server_guid = NULL; } else { _dbus_list_remove (&shared_connections_no_guid, connection); } _DBUS_UNLOCK (shared_connections); /* remove our reference held on all shareable connections */ _dbus_connection_unref_unlocked (connection); } static DBusConnection* connection_try_from_address_entry (DBusAddressEntry *entry, DBusError *error) { DBusTransport *transport; DBusConnection *connection; transport = _dbus_transport_open (entry, error); if (transport == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } connection = _dbus_connection_new_for_transport (transport); _dbus_transport_unref (transport); if (connection == NULL) { _DBUS_SET_OOM (error); return NULL; } #ifndef DBUS_DISABLE_CHECKS _dbus_assert (!connection->have_connection_lock); #endif return connection; } /* * If the shared parameter is true, then any existing connection will * be used (and if a new connection is created, it will be available * for use by others). If the shared parameter is false, a new * connection will always be created, and the new connection will * never be returned to other callers. * * @param address the address * @param shared whether the connection is shared or private * @param error error return * @returns the connection or #NULL on error */ static DBusConnection* _dbus_connection_open_internal (const char *address, dbus_bool_t shared, DBusError *error) { DBusConnection *connection; DBusAddressEntry **entries; DBusError tmp_error = DBUS_ERROR_INIT; DBusError first_error = DBUS_ERROR_INIT; int len, i; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("opening %s connection to: %s\n", shared ? "shared" : "private", address); if (!dbus_parse_address (address, &entries, &len, error)) return NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); connection = NULL; for (i = 0; i < len; i++) { if (shared) { if (!connection_lookup_shared (entries[i], &connection)) _DBUS_SET_OOM (&tmp_error); } if (connection == NULL) { connection = connection_try_from_address_entry (entries[i], &tmp_error); if (connection != NULL && shared) { const char *guid; connection->shareable = TRUE; /* guid may be NULL */ guid = dbus_address_entry_get_value (entries[i], "guid"); CONNECTION_LOCK (connection); if (!connection_record_shared_unlocked (connection, guid)) { _DBUS_SET_OOM (&tmp_error); _dbus_connection_close_possibly_shared_and_unlock (connection); dbus_connection_unref (connection); connection = NULL; } else CONNECTION_UNLOCK (connection); } } if (connection) break; _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); if (i == 0) dbus_move_error (&tmp_error, &first_error); else dbus_error_free (&tmp_error); } _DBUS_ASSERT_ERROR_IS_CLEAR (error); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); if (connection == NULL) { _DBUS_ASSERT_ERROR_IS_SET (&first_error); dbus_move_error (&first_error, error); } else dbus_error_free (&first_error); dbus_address_entries_free (entries); return connection; } /** * Closes a shared OR private connection, while dbus_connection_close() can * only be used on private connections. Should only be called by the * dbus code that owns the connection - an owner must be known, * the open/close state is like malloc/free, not like ref/unref. * * @param connection the connection */ void _dbus_connection_close_possibly_shared (DBusConnection *connection) { _dbus_assert (connection != NULL); _dbus_assert (connection->generation == _dbus_current_generation); CONNECTION_LOCK (connection); _dbus_connection_close_possibly_shared_and_unlock (connection); } static DBusPreallocatedSend* _dbus_connection_preallocate_send_unlocked (DBusConnection *connection) { DBusPreallocatedSend *preallocated; HAVE_LOCK_CHECK (connection); _dbus_assert (connection != NULL); preallocated = dbus_new (DBusPreallocatedSend, 1); if (preallocated == NULL) return NULL; preallocated->queue_link = _dbus_list_alloc_link (NULL); if (preallocated->queue_link == NULL) goto failed_0; preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter); if (preallocated->counter_link == NULL) goto failed_1; _dbus_counter_ref (preallocated->counter_link->data); preallocated->connection = connection; return preallocated; failed_1: _dbus_list_free_link (preallocated->queue_link); failed_0: dbus_free (preallocated); return NULL; } /* Called with lock held, does not update dispatch status */ static void _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *connection, DBusPreallocatedSend *preallocated, DBusMessage *message, dbus_uint32_t *client_serial) { dbus_uint32_t serial; preallocated->queue_link->data = message; _dbus_list_prepend_link (&connection->outgoing_messages, preallocated->queue_link); /* It's OK that we'll never call the notify function, because for the * outgoing limit, there isn't one */ _dbus_message_add_counter_link (message, preallocated->counter_link); dbus_free (preallocated); preallocated = NULL; dbus_message_ref (message); connection->n_outgoing += 1; _dbus_verbose ("Message %p (%s %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message), dbus_message_get_destination (message) ? dbus_message_get_destination (message) : "null", connection, connection->n_outgoing); if (dbus_message_get_serial (message) == 0) { serial = _dbus_connection_get_next_client_serial (connection); dbus_message_set_serial (message, serial); if (client_serial) *client_serial = serial; } else { if (client_serial) *client_serial = dbus_message_get_serial (message); } _dbus_verbose ("Message %p serial is %u\n", message, dbus_message_get_serial (message)); dbus_message_lock (message); /* Now we need to run an iteration to hopefully just write the messages * out immediately, and otherwise get them queued up */ _dbus_connection_do_iteration_unlocked (connection, NULL, DBUS_ITERATION_DO_WRITING, -1); /* If stuff is still queued up, be sure we wake up the main loop */ if (connection->n_outgoing > 0) _dbus_connection_wakeup_mainloop (connection); } static void _dbus_connection_send_preallocated_and_unlock (DBusConnection *connection, DBusPreallocatedSend *preallocated, DBusMessage *message, dbus_uint32_t *client_serial) { DBusDispatchStatus status; HAVE_LOCK_CHECK (connection); _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated, message, client_serial); _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); } /** * Like dbus_connection_send(), but assumes the connection * is already locked on function entry, and unlocks before returning. * * @param connection the connection * @param message the message to send * @param client_serial return location for client serial of sent message * @returns #FALSE on out-of-memory */ dbus_bool_t _dbus_connection_send_and_unlock (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial) { DBusPreallocatedSend *preallocated; _dbus_assert (connection != NULL); _dbus_assert (message != NULL); preallocated = _dbus_connection_preallocate_send_unlocked (connection); if (preallocated == NULL) { CONNECTION_UNLOCK (connection); return FALSE; } _dbus_connection_send_preallocated_and_unlock (connection, preallocated, message, client_serial); return TRUE; } /** * Used internally to handle the semantics of dbus_server_set_new_connection_function(). * If the new connection function does not ref the connection, we want to close it. * * A bit of a hack, probably the new connection function should have returned a value * for whether to close, or should have had to close the connection itself if it * didn't want it. * * But, this works OK as long as the new connection function doesn't do anything * crazy like keep the connection around without ref'ing it. * * We have to lock the connection across refcount check and close in case * the new connection function spawns a thread that closes and unrefs. * In that case, if the app thread * closes and unrefs first, we'll harmlessly close again; if the app thread * still has the ref, we'll close and then the app will close harmlessly. * If the app unrefs without closing, the app is broken since if the * app refs from the new connection function it is supposed to also close. * * If we didn't atomically check the refcount and close with the lock held * though, we could screw this up. * * @param connection the connection */ void _dbus_connection_close_if_only_one_ref (DBusConnection *connection) { dbus_int32_t refcount; CONNECTION_LOCK (connection); refcount = _dbus_atomic_get (&connection->refcount); /* The caller should have at least one ref */ _dbus_assert (refcount >= 1); if (refcount == 1) _dbus_connection_close_possibly_shared_and_unlock (connection); else CONNECTION_UNLOCK (connection); } /** * When a function that blocks has been called with a timeout, and we * run out of memory, the time to wait for memory is based on the * timeout. If the caller was willing to block a long time we wait a * relatively long time for memory, if they were only willing to block * briefly then we retry for memory at a rapid rate. * * @param timeout_milliseconds the timeout requested for blocking */ static void _dbus_memory_pause_based_on_timeout (int timeout_milliseconds) { if (timeout_milliseconds == -1) _dbus_sleep_milliseconds (1000); else if (timeout_milliseconds < 100) ; /* just busy loop */ else if (timeout_milliseconds <= 1000) _dbus_sleep_milliseconds (timeout_milliseconds / 3); else _dbus_sleep_milliseconds (1000); } static DBusMessage * generate_local_error_message (dbus_uint32_t serial, char *error_name, char *error_msg) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (!message) goto out; if (!dbus_message_set_error_name (message, error_name)) { dbus_message_unref (message); message = NULL; goto out; } dbus_message_set_no_reply (message, TRUE); if (!dbus_message_set_reply_serial (message, serial)) { dbus_message_unref (message); message = NULL; goto out; } if (error_msg != NULL) { DBusMessageIter iter; dbus_message_iter_init_append (message, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &error_msg)) { dbus_message_unref (message); message = NULL; goto out; } } out: return message; } /* * Peek the incoming queue to see if we got reply for a specific serial */ static dbus_bool_t _dbus_connection_peek_for_reply_unlocked (DBusConnection *connection, dbus_uint32_t client_serial) { DBusList *link; HAVE_LOCK_CHECK (connection); link = _dbus_list_get_first_link (&connection->incoming_messages); while (link != NULL) { DBusMessage *reply = link->data; if (dbus_message_get_reply_serial (reply) == client_serial) { _dbus_verbose ("%s reply to %d found in queue\n", _DBUS_FUNCTION_NAME, client_serial); return TRUE; } link = _dbus_list_get_next_link (&connection->incoming_messages, link); } return FALSE; } /* This is slightly strange since we can pop a message here without * the dispatch lock. */ static DBusMessage* check_for_reply_unlocked (DBusConnection *connection, dbus_uint32_t client_serial) { DBusList *link; HAVE_LOCK_CHECK (connection); link = _dbus_list_get_first_link (&connection->incoming_messages); while (link != NULL) { DBusMessage *reply = link->data; if (dbus_message_get_reply_serial (reply) == client_serial) { _dbus_list_remove_link (&connection->incoming_messages, link); connection->n_incoming -= 1; return reply; } link = _dbus_list_get_next_link (&connection->incoming_messages, link); } return NULL; } static void connection_timeout_and_complete_all_pending_calls_unlocked (DBusConnection *connection) { /* We can't iterate over the hash in the normal way since we'll be * dropping the lock for each item. So we restart the * iter each time as we drain the hash table. */ while (_dbus_hash_table_get_n_entries (connection->pending_replies) > 0) { DBusPendingCall *pending; DBusHashIter iter; _dbus_hash_iter_init (connection->pending_replies, &iter); _dbus_hash_iter_next (&iter); pending = _dbus_hash_iter_get_value (&iter); _dbus_pending_call_ref_unlocked (pending); _dbus_pending_call_queue_timeout_error_unlocked (pending, connection); if (_dbus_pending_call_is_timeout_added_unlocked (pending)) _dbus_connection_remove_timeout_unlocked (connection, _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); _dbus_hash_iter_remove_entry (&iter); _dbus_pending_call_unref_and_unlock (pending); CONNECTION_LOCK (connection); } HAVE_LOCK_CHECK (connection); } static void complete_pending_call_and_unlock (DBusConnection *connection, DBusPendingCall *pending, DBusMessage *message) { _dbus_pending_call_set_reply_unlocked (pending, message); _dbus_pending_call_ref_unlocked (pending); /* in case there's no app with a ref held */ _dbus_connection_detach_pending_call_and_unlock (connection, pending); /* Must be called unlocked since it invokes app callback */ _dbus_pending_call_complete (pending); dbus_pending_call_unref (pending); } static dbus_bool_t check_for_reply_and_update_dispatch_unlocked (DBusConnection *connection, DBusPendingCall *pending) { DBusMessage *reply; DBusDispatchStatus status; reply = check_for_reply_unlocked (connection, _dbus_pending_call_get_reply_serial_unlocked (pending)); if (reply != NULL) { _dbus_verbose ("checked for reply\n"); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); complete_pending_call_and_unlock (connection, pending, reply); dbus_message_unref (reply); CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_pending_call_unref (pending); return TRUE; } return FALSE; } /** * Blocks until a pending call times out or gets a reply. * * Does not re-enter the main loop or run filter/path-registered * callbacks. The reply to the message will not be seen by * filter callbacks. * * Returns immediately if pending call already got a reply. * * @todo could use performance improvements (it keeps scanning * the whole message queue for example) * * @param pending the pending call we block for a reply on */ void _dbus_connection_block_pending_call (DBusPendingCall *pending) { long start_tv_sec, start_tv_usec; long tv_sec, tv_usec; DBusDispatchStatus status; DBusConnection *connection; dbus_uint32_t client_serial; DBusTimeout *timeout; int timeout_milliseconds, elapsed_milliseconds; _dbus_assert (pending != NULL); if (dbus_pending_call_get_completed (pending)) return; dbus_pending_call_ref (pending); /* necessary because the call could be canceled */ connection = _dbus_pending_call_get_connection_and_lock (pending); /* Flush message queue - note, can affect dispatch status */ _dbus_connection_flush_unlocked (connection); client_serial = _dbus_pending_call_get_reply_serial_unlocked (pending); /* note that timeout_milliseconds is limited to a smallish value * in _dbus_pending_call_new() so overflows aren't possible * below */ timeout = _dbus_pending_call_get_timeout_unlocked (pending); _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec); if (timeout) { timeout_milliseconds = dbus_timeout_get_interval (timeout); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block %d milliseconds for reply serial %u from %ld sec %ld usec\n", timeout_milliseconds, client_serial, start_tv_sec, start_tv_usec); } else { timeout_milliseconds = -1; _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block for reply serial %u\n", client_serial); } /* check to see if we already got the data off the socket */ /* from another blocked pending call */ if (check_for_reply_and_update_dispatch_unlocked (connection, pending)) return; /* Now we wait... */ /* always block at least once as we know we don't have the reply yet */ _dbus_connection_do_iteration_unlocked (connection, pending, DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK, timeout_milliseconds); recheck_status: _dbus_verbose ("top of recheck\n"); HAVE_LOCK_CHECK (connection); /* queue messages and get status */ status = _dbus_connection_get_dispatch_status_unlocked (connection); /* the get_completed() is in case a dispatch() while we were blocking * got the reply instead of us. */ if (_dbus_pending_call_get_completed_unlocked (pending)) { _dbus_verbose ("Pending call completed by dispatch\n"); _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_pending_call_unref (pending); return; } if (status == DBUS_DISPATCH_DATA_REMAINS) { if (check_for_reply_and_update_dispatch_unlocked (connection, pending)) return; } _dbus_get_monotonic_time (&tv_sec, &tv_usec); elapsed_milliseconds = (tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000; if (!_dbus_connection_get_is_connected_unlocked (connection)) { DBusMessage *error_msg; error_msg = generate_local_error_message (client_serial, DBUS_ERROR_DISCONNECTED, "Connection was disconnected before a reply was received"); /* on OOM error_msg is set to NULL */ complete_pending_call_and_unlock (connection, pending, error_msg); dbus_pending_call_unref (pending); return; } else if (connection->disconnect_message_link == NULL) _dbus_verbose ("dbus_connection_send_with_reply_and_block(): disconnected\n"); else if (timeout == NULL) { if (status == DBUS_DISPATCH_NEED_MEMORY) { /* Try sleeping a bit, as we aren't sure we need to block for reading, * we may already have a reply in the buffer and just can't process * it. */ _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); } else { /* block again, we don't have the reply buffered yet. */ _dbus_connection_do_iteration_unlocked (connection, pending, DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK, timeout_milliseconds - elapsed_milliseconds); } goto recheck_status; } else if (tv_sec < start_tv_sec) _dbus_verbose ("dbus_connection_send_with_reply_and_block(): clock set backward\n"); else if (elapsed_milliseconds < timeout_milliseconds) { _dbus_verbose ("dbus_connection_send_with_reply_and_block(): %d milliseconds remain\n", timeout_milliseconds - elapsed_milliseconds); if (status == DBUS_DISPATCH_NEED_MEMORY) { /* Try sleeping a bit, as we aren't sure we need to block for reading, * we may already have a reply in the buffer and just can't process * it. */ _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); } else { /* block again, we don't have the reply buffered yet. */ _dbus_connection_do_iteration_unlocked (connection, NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK, timeout_milliseconds - elapsed_milliseconds); } goto recheck_status; } _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %d milliseconds and got no reply\n", elapsed_milliseconds); _dbus_assert (!_dbus_pending_call_get_completed_unlocked (pending)); /* unlock and call user code */ complete_pending_call_and_unlock (connection, pending, NULL); /* update user code on dispatch status */ CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_pending_call_unref (pending); } /** * Return how many file descriptors are pending in the loader * * @param connection the connection */ int _dbus_connection_get_pending_fds_count (DBusConnection *connection) { return _dbus_transport_get_pending_fds_count (connection->transport); } /** * Register a function to be called whenever the number of pending file * descriptors in the loader change. * * @param connection the connection * @param callback the callback */ void _dbus_connection_set_pending_fds_function (DBusConnection *connection, DBusPendingFdsChangeFunction callback, void *data) { _dbus_transport_set_pending_fds_function (connection->transport, callback, data); } /** @} */ /** * @addtogroup DBusConnection * * @{ */ /** * Gets a connection to a remote address. If a connection to the given * address already exists, returns the existing connection with its * reference count incremented. Otherwise, returns a new connection * and saves the new connection for possible re-use if a future call * to dbus_connection_open() asks to connect to the same server. * * Use dbus_connection_open_private() to get a dedicated connection * not shared with other callers of dbus_connection_open(). * * If the open fails, the function returns #NULL, and provides a * reason for the failure in the error parameter. Pass #NULL for the * error parameter if you aren't interested in the reason for * failure. * * Because this connection is shared, no user of the connection * may call dbus_connection_close(). However, when you are done with the * connection you should call dbus_connection_unref(). * * @note Prefer dbus_connection_open() to dbus_connection_open_private() * unless you have good reason; connections are expensive enough * that it's wasteful to create lots of connections to the same * server. * * @param address the address. * @param error address where an error can be returned. * @returns new connection, or #NULL on failure. */ DBusConnection* dbus_connection_open (const char *address, DBusError *error) { DBusConnection *connection; _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); connection = _dbus_connection_open_internal (address, TRUE, error); return connection; } /** * Opens a new, dedicated connection to a remote address. Unlike * dbus_connection_open(), always creates a new connection. * This connection will not be saved or recycled by libdbus. * * If the open fails, the function returns #NULL, and provides a * reason for the failure in the error parameter. Pass #NULL for the * error parameter if you aren't interested in the reason for * failure. * * When you are done with this connection, you must * dbus_connection_close() to disconnect it, * and dbus_connection_unref() to free the connection object. * * (The dbus_connection_close() can be skipped if the * connection is already known to be disconnected, for example * if you are inside a handler for the Disconnected signal.) * * @note Prefer dbus_connection_open() to dbus_connection_open_private() * unless you have good reason; connections are expensive enough * that it's wasteful to create lots of connections to the same * server. * * @param address the address. * @param error address where an error can be returned. * @returns new connection, or #NULL on failure. */ DBusConnection* dbus_connection_open_private (const char *address, DBusError *error) { DBusConnection *connection; _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); connection = _dbus_connection_open_internal (address, FALSE, error); return connection; } /** * Increments the reference count of a DBusConnection. * * @param connection the connection. * @returns the connection. */ DBusConnection * dbus_connection_ref (DBusConnection *connection) { dbus_int32_t old_refcount; _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_fail (connection->generation == _dbus_current_generation, NULL); old_refcount = _dbus_atomic_inc (&connection->refcount); _dbus_connection_trace_ref (connection, old_refcount, old_refcount + 1, "ref"); return connection; } static void free_outgoing_message (void *element, void *data) { DBusMessage *message = element; DBusConnection *connection = data; _dbus_message_remove_counter (message, connection->outgoing_counter); dbus_message_unref (message); } /* This is run without the mutex held, but after the last reference * to the connection has been dropped we should have no thread-related * problems */ static void _dbus_connection_last_unref (DBusConnection *connection) { DBusList *link; _dbus_verbose ("Finalizing connection %p\n", connection); _dbus_assert (_dbus_atomic_get (&connection->refcount) == 0); /* You have to disconnect the connection before unref:ing it. Otherwise * you won't get the disconnected message. */ _dbus_assert (!_dbus_transport_get_is_connected (connection->transport)); _dbus_assert (connection->server_guid == NULL); /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */ _dbus_object_tree_free_all_unlocked (connection->objects); dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); dbus_connection_set_wakeup_main_function (connection, NULL, NULL, NULL); dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL); dbus_connection_set_windows_user_function (connection, NULL, NULL, NULL); _dbus_watch_list_free (connection->watches); connection->watches = NULL; _dbus_timeout_list_free (connection->timeouts); connection->timeouts = NULL; _dbus_data_slot_list_free (&connection->slot_list); link = _dbus_list_get_first_link (&connection->filter_list); while (link != NULL) { DBusMessageFilter *filter = link->data; DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link); filter->function = NULL; _dbus_message_filter_unref (filter); /* calls app callback */ link->data = NULL; link = next; } _dbus_list_clear (&connection->filter_list); /* ---- Done with stuff that invokes application callbacks */ _dbus_object_tree_unref (connection->objects); _dbus_hash_table_unref (connection->pending_replies); connection->pending_replies = NULL; _dbus_list_clear (&connection->filter_list); _dbus_list_foreach (&connection->outgoing_messages, free_outgoing_message, connection); _dbus_list_clear (&connection->outgoing_messages); _dbus_list_foreach (&connection->incoming_messages, (DBusForeachFunction) dbus_message_unref, NULL); _dbus_list_clear (&connection->incoming_messages); _dbus_counter_unref (connection->outgoing_counter); _dbus_transport_unref (connection->transport); if (connection->disconnect_message_link) { DBusMessage *message = connection->disconnect_message_link->data; dbus_message_unref (message); _dbus_list_free_link (connection->disconnect_message_link); } _dbus_condvar_free_at_location (&connection->dispatch_cond); _dbus_condvar_free_at_location (&connection->io_path_cond); _dbus_cmutex_free_at_location (&connection->io_path_mutex); _dbus_cmutex_free_at_location (&connection->dispatch_mutex); _dbus_rmutex_free_at_location (&connection->slot_mutex); _dbus_rmutex_free_at_location (&connection->mutex); dbus_free (connection); } /** * Decrements the reference count of a DBusConnection, and finalizes * it if the count reaches zero. * * Note: it is a bug to drop the last reference to a connection that * is still connected. * * For shared connections, libdbus will own a reference * as long as the connection is connected, so you can know that either * you don't have the last reference, or it's OK to drop the last reference. * Most connections are shared. dbus_connection_open() and dbus_bus_get() * return shared connections. * * For private connections, the creator of the connection must arrange for * dbus_connection_close() to be called prior to dropping the last reference. * Private connections come from dbus_connection_open_private() or dbus_bus_get_private(). * * @param connection the connection. */ void dbus_connection_unref (DBusConnection *connection) { dbus_int32_t old_refcount; _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (connection->generation == _dbus_current_generation); old_refcount = _dbus_atomic_dec (&connection->refcount); _dbus_connection_trace_ref (connection, old_refcount, old_refcount - 1, "unref"); if (old_refcount == 1) { #ifndef DBUS_DISABLE_CHECKS if (_dbus_transport_get_is_connected (connection->transport)) { _dbus_warn_check_failed ("The last reference on a connection was dropped without closing the connection. This is a bug in an application. See dbus_connection_unref() documentation for details.\n%s", connection->shareable ? "Most likely, the application called unref() too many times and removed a reference belonging to libdbus, since this is a shared connection.\n" : "Most likely, the application was supposed to call dbus_connection_close(), since this is a private connection.\n"); return; } #endif _dbus_connection_last_unref (connection); } } /* * Note that the transport can disconnect itself (other end drops us) * and in that case this function never runs. So this function must * not do anything more than disconnect the transport and update the * dispatch status. * * If the transport self-disconnects, then we assume someone will * dispatch the connection to cause the dispatch status update. */ static void _dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection) { DBusDispatchStatus status; HAVE_LOCK_CHECK (connection); _dbus_verbose ("Disconnecting %p\n", connection); /* We need to ref because update_dispatch_status_and_unlock will unref * the connection if it was shared and libdbus was the only remaining * refcount holder. */ _dbus_connection_ref_unlocked (connection); _dbus_transport_disconnect (connection->transport); /* This has the side effect of queuing the disconnect message link * (unless we don't have enough memory, possibly, so don't assert it). * After the disconnect message link is queued, dbus_bus_get/dbus_connection_open * should never again return the newly-disconnected connection. * * However, we only unref the shared connection and exit_on_disconnect when * the disconnect message reaches the head of the message queue, * NOT when it's first queued. */ status = _dbus_connection_get_dispatch_status_unlocked (connection); /* This calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); /* Could also call out to user code */ dbus_connection_unref (connection); } /** * Closes a private connection, so no further data can be sent or received. * This disconnects the transport (such as a socket) underlying the * connection. * * Attempts to send messages after closing a connection are safe, but will result in * error replies generated locally in libdbus. * * This function does not affect the connection's reference count. It's * safe to close a connection more than once; all calls after the * first do nothing. It's impossible to "reopen" a connection, a * new connection must be created. This function may result in a call * to the DBusDispatchStatusFunction set with * dbus_connection_set_dispatch_status_function(), as the disconnect * message it generates needs to be dispatched. * * If a connection is dropped by the remote application, it will * close itself. * * You must close a connection prior to releasing the last reference to * the connection. If you dbus_connection_unref() for the last time * without closing the connection, the results are undefined; it * is a bug in your program and libdbus will try to print a warning. * * You may not close a shared connection. Connections created with * dbus_connection_open() or dbus_bus_get() are shared. * These connections are owned by libdbus, and applications should * only unref them, never close them. Applications can know it is * safe to unref these connections because libdbus will be holding a * reference as long as the connection is open. Thus, either the * connection is closed and it is OK to drop the last reference, * or the connection is open and the app knows it does not have the * last reference. * * Connections created with dbus_connection_open_private() or * dbus_bus_get_private() are not kept track of or referenced by * libdbus. The creator of these connections is responsible for * calling dbus_connection_close() prior to releasing the last * reference, if the connection is not already disconnected. * * @param connection the private (unshared) connection to close */ void dbus_connection_close (DBusConnection *connection) { _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (connection->generation == _dbus_current_generation); CONNECTION_LOCK (connection); #ifndef DBUS_DISABLE_CHECKS if (connection->shareable) { CONNECTION_UNLOCK (connection); _dbus_warn_check_failed ("Applications must not close shared connections - see dbus_connection_close() docs. This is a bug in the application.\n"); return; } #endif _dbus_connection_close_possibly_shared_and_unlock (connection); } static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); return _dbus_transport_get_is_connected (connection->transport); } /** * Gets whether the connection is currently open. A connection may * become disconnected when the remote application closes its end, or * exits; a connection may also be disconnected with * dbus_connection_close(). * * There are not separate states for "closed" and "disconnected," the two * terms are synonymous. This function should really be called * get_is_open() but for historical reasons is not. * * @param connection the connection. * @returns #TRUE if the connection is still alive. */ dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection) { dbus_bool_t res; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); res = _dbus_connection_get_is_connected_unlocked (connection); CONNECTION_UNLOCK (connection); return res; } /** * Gets whether the connection was authenticated. (Note that * if the connection was authenticated then disconnected, * this function still returns #TRUE) * * @param connection the connection * @returns #TRUE if the connection was ever authenticated */ dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection) { dbus_bool_t res; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); res = _dbus_transport_try_to_authenticate (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Gets whether the connection is not authenticated as a specific * user. If the connection is not authenticated, this function * returns #TRUE, and if it is authenticated but as an anonymous user, * it returns #TRUE. If it is authenticated as a specific user, then * this returns #FALSE. (Note that if the connection was authenticated * as anonymous then disconnected, this function still returns #TRUE.) * * If the connection is not anonymous, you can use * dbus_connection_get_unix_user() and * dbus_connection_get_windows_user() to see who it's authorized as. * * If you want to prevent non-anonymous authorization, use * dbus_server_set_auth_mechanisms() to remove the mechanisms that * allow proving user identity (i.e. only allow the ANONYMOUS * mechanism). * * @param connection the connection * @returns #TRUE if not authenticated or authenticated as anonymous */ dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection *connection) { dbus_bool_t res; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); res = _dbus_transport_get_is_anonymous (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Gets the ID of the server address we are authenticated to, if this * connection is on the client side. If the connection is on the * server side, this will always return #NULL - use dbus_server_get_id() * to get the ID of your own server, if you are the server side. * * If a client-side connection is not authenticated yet, the ID may be * available if it was included in the server address, but may not be * available. The only way to be sure the server ID is available * is to wait for authentication to complete. * * In general, each mode of connecting to a given server will have * its own ID. So for example, if the session bus daemon is listening * on UNIX domain sockets and on TCP, then each of those modalities * will have its own server ID. * * If you want an ID that identifies an entire session bus, look at * dbus_bus_get_id() instead (which is just a convenience wrapper * around the org.freedesktop.DBus.GetId method invoked on the bus). * * You can also get a machine ID; see dbus_get_local_machine_id() to * get the machine you are on. There isn't a convenience wrapper, but * you can invoke org.freedesktop.DBus.Peer.GetMachineId on any peer * to get the machine ID on the other end. * * The D-Bus specification describes the server ID and other IDs in a * bit more detail. * * @param connection the connection * @returns the server ID or #NULL if no memory or the connection is server-side */ char* dbus_connection_get_server_id (DBusConnection *connection) { char *id; _dbus_return_val_if_fail (connection != NULL, NULL); CONNECTION_LOCK (connection); id = _dbus_strdup (_dbus_transport_get_server_id (connection->transport)); CONNECTION_UNLOCK (connection); return id; } /** * Tests whether a certain type can be send via the connection. This * will always return TRUE for all types, with the exception of * DBUS_TYPE_UNIX_FD. The function will return TRUE for * DBUS_TYPE_UNIX_FD only on systems that know Unix file descriptors * and can send them via the chosen transport and when the remote side * supports this. * * This function can be used to do runtime checking for types that * might be unknown to the specific D-Bus client implementation * version, i.e. it will return FALSE for all types this * implementation does not know, including invalid or reserved types. * * @param connection the connection * @param type the type to check * @returns TRUE if the type may be send via the connection */ dbus_bool_t dbus_connection_can_send_type(DBusConnection *connection, int type) { _dbus_return_val_if_fail (connection != NULL, FALSE); if (!dbus_type_is_valid (type)) return FALSE; if (type != DBUS_TYPE_UNIX_FD) return TRUE; #ifdef HAVE_UNIX_FD_PASSING { dbus_bool_t b; CONNECTION_LOCK(connection); b = _dbus_transport_can_pass_unix_fd(connection->transport); CONNECTION_UNLOCK(connection); return b; } #endif return FALSE; } /** * Set whether _exit() should be called when the connection receives a * disconnect signal. The call to _exit() comes after any handlers for * the disconnect signal run; handlers can cancel the exit by calling * this function. * * By default, exit_on_disconnect is #FALSE; but for message bus * connections returned from dbus_bus_get() it will be toggled on * by default. * * @param connection the connection * @param exit_on_disconnect #TRUE if _exit() should be called after a disconnect signal */ void dbus_connection_set_exit_on_disconnect (DBusConnection *connection, dbus_bool_t exit_on_disconnect) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); connection->exit_on_disconnect = exit_on_disconnect != FALSE; CONNECTION_UNLOCK (connection); } /** * Preallocates resources needed to send a message, allowing the message * to be sent without the possibility of memory allocation failure. * Allows apps to create a future guarantee that they can send * a message regardless of memory shortages. * * @param connection the connection we're preallocating for. * @returns the preallocated resources, or #NULL */ DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection *connection) { DBusPreallocatedSend *preallocated; _dbus_return_val_if_fail (connection != NULL, NULL); CONNECTION_LOCK (connection); preallocated = _dbus_connection_preallocate_send_unlocked (connection); CONNECTION_UNLOCK (connection); return preallocated; } /** * Frees preallocated message-sending resources from * dbus_connection_preallocate_send(). Should only * be called if the preallocated resources are not used * to send a message. * * @param connection the connection * @param preallocated the resources */ void dbus_connection_free_preallocated_send (DBusConnection *connection, DBusPreallocatedSend *preallocated) { _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (preallocated != NULL); _dbus_return_if_fail (connection == preallocated->connection); _dbus_list_free_link (preallocated->queue_link); _dbus_counter_unref (preallocated->counter_link->data); _dbus_list_free_link (preallocated->counter_link); dbus_free (preallocated); } /** * Sends a message using preallocated resources. This function cannot fail. * It works identically to dbus_connection_send() in other respects. * Preallocated resources comes from dbus_connection_preallocate_send(). * This function "consumes" the preallocated resources, they need not * be freed separately. * * @param connection the connection * @param preallocated the preallocated resources * @param message the message to send * @param client_serial return location for client serial assigned to the message */ void dbus_connection_send_preallocated (DBusConnection *connection, DBusPreallocatedSend *preallocated, DBusMessage *message, dbus_uint32_t *client_serial) { _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (preallocated != NULL); _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (preallocated->connection == connection); _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL || dbus_message_get_member (message) != NULL); _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL || (dbus_message_get_interface (message) != NULL && dbus_message_get_member (message) != NULL)); CONNECTION_LOCK (connection); #ifdef HAVE_UNIX_FD_PASSING if (!_dbus_transport_can_pass_unix_fd(connection->transport) && message->n_unix_fds > 0) { /* Refuse to send fds on a connection that cannot handle them. Unfortunately we cannot return a proper error here, so the best we can is just return. */ CONNECTION_UNLOCK (connection); return; } #endif _dbus_connection_send_preallocated_and_unlock (connection, preallocated, message, client_serial); } static dbus_bool_t _dbus_connection_send_unlocked_no_update (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial) { DBusPreallocatedSend *preallocated; _dbus_assert (connection != NULL); _dbus_assert (message != NULL); preallocated = _dbus_connection_preallocate_send_unlocked (connection); if (preallocated == NULL) return FALSE; _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated, message, client_serial); return TRUE; } /** * Adds a message to the outgoing message queue. Does not block to * write the message to the network; that happens asynchronously. To * force the message to be written, call dbus_connection_flush() however * it is not necessary to call dbus_connection_flush() by hand; the * message will be sent the next time the main loop is run. * dbus_connection_flush() should only be used, for example, if * the application was expected to exit before running the main loop. * * Because this only queues the message, the only reason it can * fail is lack of memory. Even if the connection is disconnected, * no error will be returned. If the function fails due to lack of memory, * it returns #FALSE. The function will never fail for other reasons; even * if the connection is disconnected, you can queue an outgoing message, * though obviously it won't be sent. * * The message serial is used by the remote application to send a * reply; see dbus_message_get_serial() or the D-Bus specification. * * dbus_message_unref() can be called as soon as this method returns * as the message queue will hold its own ref until the message is sent. * * @param connection the connection. * @param message the message to write. * @param serial return location for message serial, or #NULL if you don't care * @returns #TRUE on success. */ dbus_bool_t dbus_connection_send (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *serial) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (message != NULL, FALSE); CONNECTION_LOCK (connection); #ifdef HAVE_UNIX_FD_PASSING if (!_dbus_transport_can_pass_unix_fd(connection->transport) && message->n_unix_fds > 0) { /* Refuse to send fds on a connection that cannot handle them. Unfortunately we cannot return a proper error here, so the best we can is just return. */ CONNECTION_UNLOCK (connection); return FALSE; } #endif return _dbus_connection_send_and_unlock (connection, message, serial); } static dbus_bool_t reply_handler_timeout (void *data) { DBusConnection *connection; DBusDispatchStatus status; DBusPendingCall *pending = data; connection = _dbus_pending_call_get_connection_and_lock (pending); _dbus_connection_ref_unlocked (connection); _dbus_pending_call_queue_timeout_error_unlocked (pending, connection); _dbus_connection_remove_timeout_unlocked (connection, _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* Unlocks, and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_connection_unref (connection); return TRUE; } /** * Queues a message to send, as with dbus_connection_send(), * but also returns a #DBusPendingCall used to receive a reply to the * message. If no reply is received in the given timeout_milliseconds, * this function expires the pending reply and generates a synthetic * error reply (generated in-process, not by the remote application) * indicating that a timeout occurred. * * A #DBusPendingCall will see a reply message before any filters or * registered object path handlers. See dbus_connection_dispatch() for * details on when handlers are run. * * A #DBusPendingCall will always see exactly one reply message, * unless it's cancelled with dbus_pending_call_cancel(). * * If #NULL is passed for the pending_return, the #DBusPendingCall * will still be generated internally, and used to track * the message reply timeout. This means a timeout error will * occur if no reply arrives, unlike with dbus_connection_send(). * * If -1 is passed for the timeout, a sane default timeout is used. -1 * is typically the best value for the timeout for this reason, unless * you want a very short or very long timeout. If #DBUS_TIMEOUT_INFINITE is * passed for the timeout, no timeout will be set and the call will block * forever. * * @warning if the connection is disconnected or you try to send Unix * file descriptors on a connection that does not support them, the * #DBusPendingCall will be set to #NULL, so be careful with this. * * @param connection the connection * @param message the message to send * @param pending_return return location for a #DBusPendingCall * object, or #NULL if connection is disconnected or when you try to * send Unix file descriptors on a connection that does not support * them. * @param timeout_milliseconds timeout in milliseconds, -1 (or * #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no * timeout * @returns #FALSE if no memory, #TRUE otherwise. * */ dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, DBusMessage *message, DBusPendingCall **pending_return, int timeout_milliseconds) { DBusPendingCall *pending; dbus_int32_t serial = -1; DBusDispatchStatus status; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); if (pending_return) *pending_return = NULL; CONNECTION_LOCK (connection); #ifdef HAVE_UNIX_FD_PASSING if (!_dbus_transport_can_pass_unix_fd(connection->transport) && message->n_unix_fds > 0) { /* Refuse to send fds on a connection that cannot handle them. Unfortunately we cannot return a proper error here, so the best we can do is return TRUE but leave *pending_return as NULL. */ CONNECTION_UNLOCK (connection); return TRUE; } #endif if (!_dbus_connection_get_is_connected_unlocked (connection)) { CONNECTION_UNLOCK (connection); return TRUE; } pending = _dbus_pending_call_new_unlocked (connection, timeout_milliseconds, reply_handler_timeout); if (pending == NULL) { CONNECTION_UNLOCK (connection); return FALSE; } /* Assign a serial to the message */ serial = dbus_message_get_serial (message); if (serial == 0) { serial = _dbus_connection_get_next_client_serial (connection); dbus_message_set_serial (message, serial); } if (!_dbus_pending_call_set_timeout_error_unlocked (pending, message, serial)) goto error; /* Insert the serial in the pending replies hash; * hash takes a refcount on DBusPendingCall. * Also, add the timeout. */ if (!_dbus_connection_attach_pending_call_unlocked (connection, pending)) goto error; if (!_dbus_connection_send_unlocked_no_update (connection, message, NULL)) { _dbus_connection_detach_pending_call_and_unlock (connection, pending); goto error_unlocked; } if (pending_return) *pending_return = pending; /* hand off refcount */ else { _dbus_connection_detach_pending_call_unlocked (connection, pending); /* we still have a ref to the pending call in this case, we unref * after unlocking, below */ } status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); if (pending_return == NULL) dbus_pending_call_unref (pending); return TRUE; error: CONNECTION_UNLOCK (connection); error_unlocked: dbus_pending_call_unref (pending); return FALSE; } /** * Sends a message and blocks a certain time period while waiting for * a reply. This function does not reenter the main loop, * i.e. messages other than the reply are queued up but not * processed. This function is used to invoke method calls on a * remote object. * * If a normal reply is received, it is returned, and removed from the * incoming message queue. If it is not received, #NULL is returned * and the error is set to #DBUS_ERROR_NO_REPLY. If an error reply is * received, it is converted to a #DBusError and returned as an error, * then the reply message is deleted and #NULL is returned. If * something else goes wrong, result is set to whatever is * appropriate, such as #DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_DISCONNECTED. * * @warning While this function blocks the calling thread will not be * processing the incoming message queue. This means you can end up * deadlocked if the application you're talking to needs you to reply * to a method. To solve this, either avoid the situation, block in a * separate thread from the main connection-dispatching thread, or use * dbus_pending_call_set_notify() to avoid blocking. * * @param connection the connection * @param message the message to send * @param timeout_milliseconds timeout in milliseconds, -1 (or * #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no * timeout * @param error return location for error message * @returns the message that is the reply or #NULL with an error code if the * function fails. */ DBusMessage* dbus_connection_send_with_reply_and_block (DBusConnection *connection, DBusMessage *message, int timeout_milliseconds, DBusError *error) { DBusMessage *reply; DBusPendingCall *pending; _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_fail (message != NULL, NULL); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL); _dbus_return_val_if_error_is_set (error, NULL); #ifdef HAVE_UNIX_FD_PASSING CONNECTION_LOCK (connection); if (!_dbus_transport_can_pass_unix_fd(connection->transport) && message->n_unix_fds > 0) { CONNECTION_UNLOCK (connection); dbus_set_error(error, DBUS_ERROR_FAILED, "Cannot send file descriptors on this connection."); return NULL; } CONNECTION_UNLOCK (connection); #endif if (!dbus_connection_send_with_reply (connection, message, &pending, timeout_milliseconds)) { _DBUS_SET_OOM (error); return NULL; } if (pending == NULL) { dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Connection is closed"); return NULL; } dbus_pending_call_block (pending); reply = dbus_pending_call_steal_reply (pending); dbus_pending_call_unref (pending); /* call_complete_and_unlock() called from pending_call_block() should * always fill this in. */ _dbus_assert (reply != NULL); if (dbus_set_error_from_message (error, reply)) { dbus_message_unref (reply); return NULL; } else return reply; } /** * Blocks until the outgoing message queue is empty. * Assumes connection lock already held. * * If you call this, you MUST call update_dispatch_status afterword... * * @param connection the connection. */ static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection) { /* We have to specify DBUS_ITERATION_DO_READING here because * otherwise we could have two apps deadlock if they are both doing * a flush(), and the kernel buffers fill up. This could change the * dispatch status. */ DBusDispatchStatus status; HAVE_LOCK_CHECK (connection); while (connection->n_outgoing > 0 && _dbus_connection_get_is_connected_unlocked (connection)) { _dbus_verbose ("doing iteration in\n"); HAVE_LOCK_CHECK (connection); _dbus_connection_do_iteration_unlocked (connection, NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_BLOCK, -1); } HAVE_LOCK_CHECK (connection); _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); HAVE_LOCK_CHECK (connection); return status; } /** * Blocks until the outgoing message queue is empty. * * @param connection the connection. */ void dbus_connection_flush (DBusConnection *connection) { /* We have to specify DBUS_ITERATION_DO_READING here because * otherwise we could have two apps deadlock if they are both doing * a flush(), and the kernel buffers fill up. This could change the * dispatch status. */ DBusDispatchStatus status; _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); status = _dbus_connection_flush_unlocked (connection); HAVE_LOCK_CHECK (connection); /* Unlocks and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); _dbus_verbose ("end\n"); } /** * This function implements dbus_connection_read_write_dispatch() and * dbus_connection_read_write() (they pass a different value for the * dispatch parameter). * * @param connection the connection * @param timeout_milliseconds max time to block or -1 for infinite * @param dispatch dispatch new messages or leave them on the incoming queue * @returns #TRUE if the disconnect message has not been processed */ static dbus_bool_t _dbus_connection_read_write_dispatch (DBusConnection *connection, int timeout_milliseconds, dbus_bool_t dispatch) { DBusDispatchStatus dstatus; dbus_bool_t progress_possible; /* Need to grab a ref here in case we're a private connection and * the user drops the last ref in a handler we call; see bug * https://bugs.freedesktop.org/show_bug.cgi?id=15635 */ dbus_connection_ref (connection); dstatus = dbus_connection_get_dispatch_status (connection); if (dispatch && dstatus == DBUS_DISPATCH_DATA_REMAINS) { _dbus_verbose ("doing dispatch\n"); dbus_connection_dispatch (connection); CONNECTION_LOCK (connection); } else if (dstatus == DBUS_DISPATCH_NEED_MEMORY) { _dbus_verbose ("pausing for memory\n"); _dbus_memory_pause_based_on_timeout (timeout_milliseconds); CONNECTION_LOCK (connection); } else { CONNECTION_LOCK (connection); if (_dbus_connection_get_is_connected_unlocked (connection)) { _dbus_verbose ("doing iteration\n"); _dbus_connection_do_iteration_unlocked (connection, NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_BLOCK, timeout_milliseconds); } } HAVE_LOCK_CHECK (connection); /* If we can dispatch, we can make progress until the Disconnected message * has been processed; if we can only read/write, we can make progress * as long as the transport is open. */ if (dispatch) progress_possible = connection->n_incoming != 0 || connection->disconnect_message_link != NULL; else progress_possible = _dbus_connection_get_is_connected_unlocked (connection); CONNECTION_UNLOCK (connection); dbus_connection_unref (connection); return progress_possible; /* TRUE if we can make more progress */ } /** * This function is intended for use with applications that don't want * to write a main loop and deal with #DBusWatch and #DBusTimeout. An * example usage would be: * * @code * while (dbus_connection_read_write_dispatch (connection, -1)) * ; // empty loop body * @endcode * * In this usage you would normally have set up a filter function to look * at each message as it is dispatched. The loop terminates when the last * message from the connection (the disconnected signal) is processed. * * If there are messages to dispatch, this function will * dbus_connection_dispatch() once, and return. If there are no * messages to dispatch, this function will block until it can read or * write, then read or write, then return. * * The way to think of this function is that it either makes some sort * of progress, or it blocks. Note that, while it is blocked on I/O, it * cannot be interrupted (even by other threads), which makes this function * unsuitable for applications that do more than just react to received * messages. * * The return value indicates whether the disconnect message has been * processed, NOT whether the connection is connected. This is * important because even after disconnecting, you want to process any * messages you received prior to the disconnect. * * @param connection the connection * @param timeout_milliseconds max time to block or -1 for infinite * @returns #TRUE if the disconnect message has not been processed */ dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection *connection, int timeout_milliseconds) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, TRUE); } /** * This function is intended for use with applications that don't want to * write a main loop and deal with #DBusWatch and #DBusTimeout. See also * dbus_connection_read_write_dispatch(). * * As long as the connection is open, this function will block until it can * read or write, then read or write, then return #TRUE. * * If the connection is closed, the function returns #FALSE. * * The return value indicates whether reading or writing is still * possible, i.e. whether the connection is connected. * * Note that even after disconnection, messages may remain in the * incoming queue that need to be * processed. dbus_connection_read_write_dispatch() dispatches * incoming messages for you; with dbus_connection_read_write() you * have to arrange to drain the incoming queue yourself. * * @param connection the connection * @param timeout_milliseconds max time to block or -1 for infinite * @returns #TRUE if still connected */ dbus_bool_t dbus_connection_read_write (DBusConnection *connection, int timeout_milliseconds) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, FALSE); } /* We need to call this anytime we pop the head of the queue, and then * update_dispatch_status_and_unlock needs to be called afterward * which will "process" the disconnected message and set * disconnected_message_processed. */ static void check_disconnected_message_arrived_unlocked (DBusConnection *connection, DBusMessage *head_of_queue) { HAVE_LOCK_CHECK (connection); /* checking that the link is NULL is an optimization to avoid the is_signal call */ if (connection->disconnect_message_link == NULL && dbus_message_is_signal (head_of_queue, DBUS_INTERFACE_LOCAL, "Disconnected")) { connection->disconnected_message_arrived = TRUE; } } /** * Returns the first-received message from the incoming message queue, * leaving it in the queue. If the queue is empty, returns #NULL. * * The caller does not own a reference to the returned message, and * must either return it using dbus_connection_return_message() or * keep it after calling dbus_connection_steal_borrowed_message(). No * one can get at the message while its borrowed, so return it as * quickly as possible and don't keep a reference to it after * returning it. If you need to keep the message, make a copy of it. * * dbus_connection_dispatch() will block if called while a borrowed * message is outstanding; only one piece of code can be playing with * the incoming queue at a time. This function will block if called * during a dbus_connection_dispatch(). * * @param connection the connection. * @returns next message in the incoming queue. */ DBusMessage* dbus_connection_borrow_message (DBusConnection *connection) { DBusDispatchStatus status; DBusMessage *message; _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_verbose ("start\n"); /* this is called for the side effect that it queues * up any messages from the transport */ status = dbus_connection_get_dispatch_status (connection); if (status != DBUS_DISPATCH_DATA_REMAINS) return NULL; CONNECTION_LOCK (connection); _dbus_connection_acquire_dispatch (connection); /* While a message is outstanding, the dispatch lock is held */ _dbus_assert (connection->message_borrowed == NULL); connection->message_borrowed = _dbus_list_get_first (&connection->incoming_messages); message = connection->message_borrowed; check_disconnected_message_arrived_unlocked (connection, message); /* Note that we KEEP the dispatch lock until the message is returned */ if (message == NULL) _dbus_connection_release_dispatch (connection); CONNECTION_UNLOCK (connection); _dbus_message_trace_ref (message, -1, -1, "dbus_connection_borrow_message"); /* We don't update dispatch status until it's returned or stolen */ return message; } /** * Used to return a message after peeking at it using * dbus_connection_borrow_message(). Only called if * message from dbus_connection_borrow_message() was non-#NULL. * * @param connection the connection * @param message the message from dbus_connection_borrow_message() */ void dbus_connection_return_message (DBusConnection *connection, DBusMessage *message) { DBusDispatchStatus status; _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (message == connection->message_borrowed); _dbus_return_if_fail (connection->dispatch_acquired); CONNECTION_LOCK (connection); _dbus_assert (message == connection->message_borrowed); connection->message_borrowed = NULL; _dbus_connection_release_dispatch (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); _dbus_message_trace_ref (message, -1, -1, "dbus_connection_return_message"); } /** * Used to keep a message after peeking at it using * dbus_connection_borrow_message(). Before using this function, see * the caveats/warnings in the documentation for * dbus_connection_pop_message(). * * @param connection the connection * @param message the message from dbus_connection_borrow_message() */ void dbus_connection_steal_borrowed_message (DBusConnection *connection, DBusMessage *message) { DBusMessage *pop_message; DBusDispatchStatus status; _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (message == connection->message_borrowed); _dbus_return_if_fail (connection->dispatch_acquired); CONNECTION_LOCK (connection); _dbus_assert (message == connection->message_borrowed); pop_message = _dbus_list_pop_first (&connection->incoming_messages); _dbus_assert (message == pop_message); (void) pop_message; /* unused unless asserting */ connection->n_incoming -= 1; _dbus_verbose ("Incoming message %p stolen from queue, %d incoming\n", message, connection->n_incoming); connection->message_borrowed = NULL; _dbus_connection_release_dispatch (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); _dbus_message_trace_ref (message, -1, -1, "dbus_connection_steal_borrowed_message"); } /* See dbus_connection_pop_message, but requires the caller to own * the lock before calling. May drop the lock while running. */ static DBusList* _dbus_connection_pop_message_link_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); _dbus_assert (connection->message_borrowed == NULL); if (connection->n_incoming > 0) { DBusList *link; link = _dbus_list_pop_first_link (&connection->incoming_messages); connection->n_incoming -= 1; _dbus_verbose ("Message %p (%s %s %s %s sig:'%s' serial:%u) removed from incoming queue %p, %d incoming\n", link->data, dbus_message_type_to_string (dbus_message_get_type (link->data)), dbus_message_get_path (link->data) ? dbus_message_get_path (link->data) : "no path", dbus_message_get_interface (link->data) ? dbus_message_get_interface (link->data) : "no interface", dbus_message_get_member (link->data) ? dbus_message_get_member (link->data) : "no member", dbus_message_get_signature (link->data), dbus_message_get_serial (link->data), connection, connection->n_incoming); _dbus_message_trace_ref (link->data, -1, -1, "_dbus_connection_pop_message_link_unlocked"); check_disconnected_message_arrived_unlocked (connection, link->data); return link; } else return NULL; } /* See dbus_connection_pop_message, but requires the caller to own * the lock before calling. May drop the lock while running. */ static DBusMessage* _dbus_connection_pop_message_unlocked (DBusConnection *connection) { DBusList *link; HAVE_LOCK_CHECK (connection); link = _dbus_connection_pop_message_link_unlocked (connection); if (link != NULL) { DBusMessage *message; message = link->data; _dbus_list_free_link (link); return message; } else return NULL; } static void _dbus_connection_putback_message_link_unlocked (DBusConnection *connection, DBusList *message_link) { HAVE_LOCK_CHECK (connection); _dbus_assert (message_link != NULL); /* You can't borrow a message while a link is outstanding */ _dbus_assert (connection->message_borrowed == NULL); /* We had to have the dispatch lock across the pop/putback */ _dbus_assert (connection->dispatch_acquired); _dbus_list_prepend_link (&connection->incoming_messages, message_link); connection->n_incoming += 1; _dbus_verbose ("Message %p (%s %s %s '%s') put back into queue %p, %d incoming\n", message_link->data, dbus_message_type_to_string (dbus_message_get_type (message_link->data)), dbus_message_get_interface (message_link->data) ? dbus_message_get_interface (message_link->data) : "no interface", dbus_message_get_member (message_link->data) ? dbus_message_get_member (message_link->data) : "no member", dbus_message_get_signature (message_link->data), connection, connection->n_incoming); _dbus_message_trace_ref (message_link->data, -1, -1, "_dbus_connection_putback_message_link_unlocked"); } /** * Returns the first-received message from the incoming message queue, * removing it from the queue. The caller owns a reference to the * returned message. If the queue is empty, returns #NULL. * * This function bypasses any message handlers that are registered, * and so using it is usually wrong. Instead, let the main loop invoke * dbus_connection_dispatch(). Popping messages manually is only * useful in very simple programs that don't share a #DBusConnection * with any libraries or other modules. * * There is a lock that covers all ways of accessing the incoming message * queue, so dbus_connection_dispatch(), dbus_connection_pop_message(), * dbus_connection_borrow_message(), etc. will all block while one of the others * in the group is running. * * @param connection the connection. * @returns next message in the incoming queue. */ DBusMessage* dbus_connection_pop_message (DBusConnection *connection) { DBusMessage *message; DBusDispatchStatus status; _dbus_verbose ("start\n"); /* this is called for the side effect that it queues * up any messages from the transport */ status = dbus_connection_get_dispatch_status (connection); if (status != DBUS_DISPATCH_DATA_REMAINS) return NULL; CONNECTION_LOCK (connection); _dbus_connection_acquire_dispatch (connection); HAVE_LOCK_CHECK (connection); message = _dbus_connection_pop_message_unlocked (connection); _dbus_verbose ("Returning popped message %p\n", message); _dbus_connection_release_dispatch (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); return message; } /** * Acquire the dispatcher. This is a separate lock so the main * connection lock can be dropped to call out to application dispatch * handlers. * * @param connection the connection. */ static void _dbus_connection_acquire_dispatch (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); _dbus_connection_ref_unlocked (connection); CONNECTION_UNLOCK (connection); _dbus_verbose ("locking dispatch_mutex\n"); _dbus_cmutex_lock (connection->dispatch_mutex); while (connection->dispatch_acquired) { _dbus_verbose ("waiting for dispatch to be acquirable\n"); _dbus_condvar_wait (connection->dispatch_cond, connection->dispatch_mutex); } _dbus_assert (!connection->dispatch_acquired); connection->dispatch_acquired = TRUE; _dbus_verbose ("unlocking dispatch_mutex\n"); _dbus_cmutex_unlock (connection->dispatch_mutex); CONNECTION_LOCK (connection); _dbus_connection_unref_unlocked (connection); } /** * Release the dispatcher when you're done with it. Only call * after you've acquired the dispatcher. Wakes up at most one * thread currently waiting to acquire the dispatcher. * * @param connection the connection. */ static void _dbus_connection_release_dispatch (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); _dbus_verbose ("locking dispatch_mutex\n"); _dbus_cmutex_lock (connection->dispatch_mutex); _dbus_assert (connection->dispatch_acquired); connection->dispatch_acquired = FALSE; _dbus_condvar_wake_one (connection->dispatch_cond); _dbus_verbose ("unlocking dispatch_mutex\n"); _dbus_cmutex_unlock (connection->dispatch_mutex); } static void _dbus_connection_failed_pop (DBusConnection *connection, DBusList *message_link) { _dbus_list_prepend_link (&connection->incoming_messages, message_link); connection->n_incoming += 1; } /* Note this may be called multiple times since we don't track whether we already did it */ static void notify_disconnected_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); /* Set the weakref in dbus-bus.c to NULL, so nobody will get a disconnected * connection from dbus_bus_get(). We make the same guarantee for * dbus_connection_open() but in a different way since we don't want to * unref right here; we instead check for connectedness before returning * the connection from the hash. */ _dbus_bus_notify_shared_connection_disconnected_unlocked (connection); /* Dump the outgoing queue, we aren't going to be able to * send it now, and we'd like accessors like * dbus_connection_get_outgoing_size() to be accurate. */ if (connection->n_outgoing > 0) { DBusList *link; _dbus_verbose ("Dropping %d outgoing messages since we're disconnected\n", connection->n_outgoing); while ((link = _dbus_list_get_last_link (&connection->outgoing_messages))) { _dbus_connection_message_sent_unlocked (connection, link->data); } } } /* Note this may be called multiple times since we don't track whether we already did it */ static DBusDispatchStatus notify_disconnected_and_dispatch_complete_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); if (connection->disconnect_message_link != NULL) { _dbus_verbose ("Sending disconnect message\n"); /* If we have pending calls, queue their timeouts - we want the Disconnected * to be the last message, after these timeouts. */ connection_timeout_and_complete_all_pending_calls_unlocked (connection); /* We haven't sent the disconnect message already, * and all real messages have been queued up. */ _dbus_connection_queue_synthesized_message_link (connection, connection->disconnect_message_link); connection->disconnect_message_link = NULL; return DBUS_DISPATCH_DATA_REMAINS; } return DBUS_DISPATCH_COMPLETE; } static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); if (connection->n_incoming > 0) return DBUS_DISPATCH_DATA_REMAINS; else if (!_dbus_transport_queue_messages (connection->transport)) return DBUS_DISPATCH_NEED_MEMORY; else { DBusDispatchStatus status; dbus_bool_t is_connected; status = _dbus_transport_get_dispatch_status (connection->transport); is_connected = _dbus_transport_get_is_connected (connection->transport); _dbus_verbose ("dispatch status = %s is_connected = %d\n", DISPATCH_STATUS_NAME (status), is_connected); if (!is_connected) { /* It's possible this would be better done by having an explicit * notification from _dbus_transport_disconnect() that would * synchronously do this, instead of waiting for the next dispatch * status check. However, probably not good to change until it causes * a problem. */ notify_disconnected_unlocked (connection); /* I'm not sure this is needed; the idea is that we want to * queue the Disconnected only after we've read all the * messages, but if we're disconnected maybe we are guaranteed * to have read them all ? */ if (status == DBUS_DISPATCH_COMPLETE) status = notify_disconnected_and_dispatch_complete_unlocked (connection); } if (status != DBUS_DISPATCH_COMPLETE) return status; else if (connection->n_incoming > 0) return DBUS_DISPATCH_DATA_REMAINS; else return DBUS_DISPATCH_COMPLETE; } } static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, DBusDispatchStatus new_status) { dbus_bool_t changed; DBusDispatchStatusFunction function; void *data; HAVE_LOCK_CHECK (connection); _dbus_connection_ref_unlocked (connection); changed = new_status != connection->last_dispatch_status; connection->last_dispatch_status = new_status; function = connection->dispatch_status_function; data = connection->dispatch_status_data; if (connection->disconnected_message_arrived && !connection->disconnected_message_processed) { connection->disconnected_message_processed = TRUE; /* this does an unref, but we have a ref * so we should not run the finalizer here * inside the lock. */ connection_forget_shared_unlocked (connection); if (connection->exit_on_disconnect) { CONNECTION_UNLOCK (connection); _dbus_verbose ("Exiting on Disconnected signal\n"); _dbus_exit (1); _dbus_assert_not_reached ("Call to exit() returned"); } } /* We drop the lock */ CONNECTION_UNLOCK (connection); if (changed && function) { _dbus_verbose ("Notifying of change to dispatch status of %p now %d (%s)\n", connection, new_status, DISPATCH_STATUS_NAME (new_status)); (* function) (connection, new_status, data); } dbus_connection_unref (connection); } /** * Gets the current state of the incoming message queue. * #DBUS_DISPATCH_DATA_REMAINS indicates that the message queue * may contain messages. #DBUS_DISPATCH_COMPLETE indicates that the * incoming queue is empty. #DBUS_DISPATCH_NEED_MEMORY indicates that * there could be data, but we can't know for sure without more * memory. * * To process the incoming message queue, use dbus_connection_dispatch() * or (in rare cases) dbus_connection_pop_message(). * * Note, #DBUS_DISPATCH_DATA_REMAINS really means that either we * have messages in the queue, or we have raw bytes buffered up * that need to be parsed. When these bytes are parsed, they * may not add up to an entire message. Thus, it's possible * to see a status of #DBUS_DISPATCH_DATA_REMAINS but not * have a message yet. * * In particular this happens on initial connection, because all sorts * of authentication protocol stuff has to be parsed before the * first message arrives. * * @param connection the connection. * @returns current dispatch status */ DBusDispatchStatus dbus_connection_get_dispatch_status (DBusConnection *connection) { DBusDispatchStatus status; _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); _dbus_verbose ("start\n"); CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); CONNECTION_UNLOCK (connection); return status; } /** * Filter funtion for handling the Peer standard interface. */ static DBusHandlerResult _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection, DBusMessage *message) { dbus_bool_t sent = FALSE; DBusMessage *ret = NULL; DBusList *expire_link; if (connection->route_peer_messages && dbus_message_get_destination (message) != NULL) { /* This means we're letting the bus route this message */ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (!dbus_message_has_interface (message, DBUS_INTERFACE_PEER)) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* Preallocate a linked-list link, so that if we need to dispose of a * message, we can attach it to the expired list */ expire_link = _dbus_list_alloc_link (NULL); if (!expire_link) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (dbus_message_is_method_call (message, DBUS_INTERFACE_PEER, "Ping")) { ret = dbus_message_new_method_return (message); if (ret == NULL) goto out; sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); } else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PEER, "GetMachineId")) { DBusString uuid; DBusError error = DBUS_ERROR_INIT; if (!_dbus_string_init (&uuid)) goto out; if (_dbus_get_local_machine_uuid_encoded (&uuid, &error)) { const char *v_STRING; ret = dbus_message_new_method_return (message); if (ret == NULL) { _dbus_string_free (&uuid); goto out; } v_STRING = _dbus_string_get_const_data (&uuid); if (dbus_message_append_args (ret, DBUS_TYPE_STRING, &v_STRING, DBUS_TYPE_INVALID)) { sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); } } else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); goto out; } else { ret = dbus_message_new_error (message, error.name, error.message); dbus_error_free (&error); if (ret == NULL) goto out; sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); } _dbus_string_free (&uuid); } else { /* We need to bounce anything else with this interface, otherwise apps * could start extending the interface and when we added extensions * here to DBusConnection we'd break those apps. */ ret = dbus_message_new_error (message, DBUS_ERROR_UNKNOWN_METHOD, "Unknown method invoked on org.freedesktop.DBus.Peer interface"); if (ret == NULL) goto out; sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); } out: if (ret == NULL) { _dbus_list_free_link (expire_link); } else { /* It'll be safe to unref the reply when we unlock */ expire_link->data = ret; _dbus_list_prepend_link (&connection->expired_messages, expire_link); } if (!sent) return DBUS_HANDLER_RESULT_NEED_MEMORY; return DBUS_HANDLER_RESULT_HANDLED; } /** * Processes all builtin filter functions * * If the spec specifies a standard interface * they should be processed from this method **/ static DBusHandlerResult _dbus_connection_run_builtin_filters_unlocked_no_update (DBusConnection *connection, DBusMessage *message) { /* We just run one filter for now but have the option to run more if the spec calls for it in the future */ return _dbus_connection_peer_filter_unlocked_no_update (connection, message); } /** * Processes any incoming data. * * If there's incoming raw data that has not yet been parsed, it is * parsed, which may or may not result in adding messages to the * incoming queue. * * The incoming data buffer is filled when the connection reads from * its underlying transport (such as a socket). Reading usually * happens in dbus_watch_handle() or dbus_connection_read_write(). * * If there are complete messages in the incoming queue, * dbus_connection_dispatch() removes one message from the queue and * processes it. Processing has three steps. * * First, any method replies are passed to #DBusPendingCall or * dbus_connection_send_with_reply_and_block() in order to * complete the pending method call. * * Second, any filters registered with dbus_connection_add_filter() * are run. If any filter returns #DBUS_HANDLER_RESULT_HANDLED * then processing stops after that filter. * * Third, if the message is a method call it is forwarded to * any registered object path handlers added with * dbus_connection_register_object_path() or * dbus_connection_register_fallback(). * * A single call to dbus_connection_dispatch() will process at most * one message; it will not clear the entire message queue. * * Be careful about calling dbus_connection_dispatch() from inside a * message handler, i.e. calling dbus_connection_dispatch() * recursively. If threads have been initialized with a recursive * mutex function, then this will not deadlock; however, it can * certainly confuse your application. * * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY * * @param connection the connection * @returns dispatch status, see dbus_connection_get_dispatch_status() */ DBusDispatchStatus dbus_connection_dispatch (DBusConnection *connection) { DBusMessage *message; DBusList *link, *filter_list_copy, *message_link; DBusHandlerResult result; DBusPendingCall *pending; dbus_int32_t reply_serial; DBusDispatchStatus status; dbus_bool_t found_object; _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); _dbus_verbose ("\n"); CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); if (status != DBUS_DISPATCH_DATA_REMAINS) { /* unlocks and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); return status; } /* We need to ref the connection since the callback could potentially * drop the last ref to it */ _dbus_connection_ref_unlocked (connection); _dbus_connection_acquire_dispatch (connection); HAVE_LOCK_CHECK (connection); message_link = _dbus_connection_pop_message_link_unlocked (connection); if (message_link == NULL) { /* another thread dispatched our stuff */ _dbus_verbose ("another thread dispatched message (during acquire_dispatch above)\n"); _dbus_connection_release_dispatch (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_connection_unref (connection); return status; } message = message_link->data; _dbus_verbose (" dispatching message %p (%s %s %s '%s')\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message)); result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* Pending call handling must be first, because if you do * dbus_connection_send_with_reply_and_block() or * dbus_pending_call_block() then no handlers/filters will be run on * the reply. We want consistent semantics in the case where we * dbus_connection_dispatch() the reply. */ reply_serial = dbus_message_get_reply_serial (message); pending = _dbus_hash_table_lookup_int (connection->pending_replies, reply_serial); if (pending) { _dbus_verbose ("Dispatching a pending reply\n"); complete_pending_call_and_unlock (connection, pending, message); pending = NULL; /* it's probably unref'd */ CONNECTION_LOCK (connection); _dbus_verbose ("pending call completed in dispatch\n"); result = DBUS_HANDLER_RESULT_HANDLED; goto out; } result = _dbus_connection_run_builtin_filters_unlocked_no_update (connection, message); if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) goto out; if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy)) { _dbus_connection_release_dispatch (connection); HAVE_LOCK_CHECK (connection); _dbus_connection_failed_pop (connection, message_link); /* unlocks and calls user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, DBUS_DISPATCH_NEED_MEMORY); dbus_connection_unref (connection); return DBUS_DISPATCH_NEED_MEMORY; } _dbus_list_foreach (&filter_list_copy, (DBusForeachFunction)_dbus_message_filter_ref, NULL); /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ CONNECTION_UNLOCK (connection); link = _dbus_list_get_first_link (&filter_list_copy); while (link != NULL) { DBusMessageFilter *filter = link->data; DBusList *next = _dbus_list_get_next_link (&filter_list_copy, link); if (filter->function == NULL) { _dbus_verbose (" filter was removed in a callback function\n"); link = next; continue; } _dbus_verbose (" running filter on message %p\n", message); result = (* filter->function) (connection, message, filter->user_data); if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) break; link = next; } _dbus_list_foreach (&filter_list_copy, (DBusForeachFunction)_dbus_message_filter_unref, NULL); _dbus_list_clear (&filter_list_copy); CONNECTION_LOCK (connection); if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) { _dbus_verbose ("No memory\n"); goto out; } else if (result == DBUS_HANDLER_RESULT_HANDLED) { _dbus_verbose ("filter handled message in dispatch\n"); goto out; } /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ _dbus_verbose (" running object path dispatch on message %p (%s %s %s '%s')\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message)); HAVE_LOCK_CHECK (connection); result = _dbus_object_tree_dispatch_and_unlock (connection->objects, message, &found_object); CONNECTION_LOCK (connection); if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) { _dbus_verbose ("object tree handled message in dispatch\n"); goto out; } if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) { DBusMessage *reply; DBusString str; DBusPreallocatedSend *preallocated; DBusList *expire_link; _dbus_verbose (" sending error %s\n", DBUS_ERROR_UNKNOWN_METHOD); if (!_dbus_string_init (&str)) { result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_verbose ("no memory for error string in dispatch\n"); goto out; } if (!_dbus_string_append_printf (&str, "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n", dbus_message_get_member (message), dbus_message_get_signature (message), dbus_message_get_interface (message))) { _dbus_string_free (&str); result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_verbose ("no memory for error string in dispatch\n"); goto out; } reply = dbus_message_new_error (message, found_object ? DBUS_ERROR_UNKNOWN_METHOD : DBUS_ERROR_UNKNOWN_OBJECT, _dbus_string_get_const_data (&str)); _dbus_string_free (&str); if (reply == NULL) { result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_verbose ("no memory for error reply in dispatch\n"); goto out; } expire_link = _dbus_list_alloc_link (reply); if (expire_link == NULL) { dbus_message_unref (reply); result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_verbose ("no memory for error send in dispatch\n"); goto out; } preallocated = _dbus_connection_preallocate_send_unlocked (connection); if (preallocated == NULL) { _dbus_list_free_link (expire_link); /* It's OK that this is finalized, because it hasn't been seen by * anything that could attach user callbacks */ dbus_message_unref (reply); result = DBUS_HANDLER_RESULT_NEED_MEMORY; _dbus_verbose ("no memory for error send in dispatch\n"); goto out; } _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated, reply, NULL); /* reply will be freed when we release the lock */ _dbus_list_prepend_link (&connection->expired_messages, expire_link); result = DBUS_HANDLER_RESULT_HANDLED; } _dbus_verbose (" done dispatching %p (%s %s %s '%s') on connection %p\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", dbus_message_get_signature (message), connection); out: if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) { _dbus_verbose ("out of memory\n"); /* Put message back, and we'll start over. * Yes this means handlers must be idempotent if they * don't return HANDLED; c'est la vie. */ _dbus_connection_putback_message_link_unlocked (connection, message_link); /* now we don't want to free them */ message_link = NULL; message = NULL; } else { _dbus_verbose (" ... done dispatching\n"); } _dbus_connection_release_dispatch (connection); HAVE_LOCK_CHECK (connection); if (message != NULL) { /* We don't want this message to count in maximum message limits when * computing the dispatch status, below. We have to drop the lock * temporarily, because finalizing a message can trigger callbacks. * * We have a reference to the connection, and we don't use any cached * pointers to the connection's internals below this point, so it should * be safe to drop the lock and take it back. */ CONNECTION_UNLOCK (connection); dbus_message_unref (message); CONNECTION_LOCK (connection); } if (message_link != NULL) _dbus_list_free_link (message_link); _dbus_verbose ("before final status update\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* unlocks and calls user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_connection_unref (connection); return status; } /** * Sets the watch functions for the connection. These functions are * responsible for making the application's main loop aware of file * descriptors that need to be monitored for events, using select() or * poll(). When using Qt, typically the DBusAddWatchFunction would * create a QSocketNotifier. When using GLib, the DBusAddWatchFunction * could call g_io_add_watch(), or could be used as part of a more * elaborate GSource. Note that when a watch is added, it may * not be enabled. * * The DBusWatchToggledFunction notifies the application that the * watch has been enabled or disabled. Call dbus_watch_get_enabled() * to check this. A disabled watch should have no effect, and enabled * watch should be added to the main loop. This feature is used * instead of simply adding/removing the watch because * enabling/disabling can be done without memory allocation. The * toggled function may be NULL if a main loop re-queries * dbus_watch_get_enabled() every time anyway. * * The DBusWatch can be queried for the file descriptor to watch using * dbus_watch_get_unix_fd() or dbus_watch_get_socket(), and for the * events to watch for using dbus_watch_get_flags(). The flags * returned by dbus_watch_get_flags() will only contain * DBUS_WATCH_READABLE and DBUS_WATCH_WRITABLE, never * DBUS_WATCH_HANGUP or DBUS_WATCH_ERROR; all watches implicitly * include a watch for hangups, errors, and other exceptional * conditions. * * Once a file descriptor becomes readable or writable, or an exception * occurs, dbus_watch_handle() should be called to * notify the connection of the file descriptor's condition. * * dbus_watch_handle() cannot be called during the * DBusAddWatchFunction, as the connection will not be ready to handle * that watch yet. * * It is not allowed to reference a DBusWatch after it has been passed * to remove_function. * * If #FALSE is returned due to lack of memory, the failure may be due * to a #FALSE return from the new add_function. If so, the * add_function may have been called successfully one or more times, * but the remove_function will also have been called to remove any * successful adds. i.e. if #FALSE is returned the net result * should be that dbus_connection_set_watch_functions() has no effect, * but the add_function and remove_function may have been called. * * @note The thread lock on DBusConnection is held while * watch functions are invoked, so inside these functions you * may not invoke any methods on DBusConnection or it will deadlock. * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/tread.html#8144 * if you encounter this issue and want to attempt writing a patch. * * @param connection the connection. * @param add_function function to begin monitoring a new descriptor. * @param remove_function function to stop monitoring a descriptor. * @param toggled_function function to notify of enable/disable * @param data data to pass to add_function and remove_function. * @param free_data_function function to be called to free the data. * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_connection_set_watch_functions (DBusConnection *connection, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); retval = _dbus_watch_list_set_functions (connection->watches, add_function, remove_function, toggled_function, data, free_data_function); CONNECTION_UNLOCK (connection); return retval; } /** * Sets the timeout functions for the connection. These functions are * responsible for making the application's main loop aware of timeouts. * When using Qt, typically the DBusAddTimeoutFunction would create a * QTimer. When using GLib, the DBusAddTimeoutFunction would call * g_timeout_add. * * The DBusTimeoutToggledFunction notifies the application that the * timeout has been enabled or disabled. Call * dbus_timeout_get_enabled() to check this. A disabled timeout should * have no effect, and enabled timeout should be added to the main * loop. This feature is used instead of simply adding/removing the * timeout because enabling/disabling can be done without memory * allocation. With Qt, QTimer::start() and QTimer::stop() can be used * to enable and disable. The toggled function may be NULL if a main * loop re-queries dbus_timeout_get_enabled() every time anyway. * Whenever a timeout is toggled, its interval may change. * * The DBusTimeout can be queried for the timer interval using * dbus_timeout_get_interval(). dbus_timeout_handle() should be called * repeatedly, each time the interval elapses, starting after it has * elapsed once. The timeout stops firing when it is removed with the * given remove_function. The timer interval may change whenever the * timeout is added, removed, or toggled. * * @note The thread lock on DBusConnection is held while * timeout functions are invoked, so inside these functions you * may not invoke any methods on DBusConnection or it will deadlock. * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 * if you encounter this issue and want to attempt writing a patch. * * @param connection the connection. * @param add_function function to add a timeout. * @param remove_function function to remove a timeout. * @param toggled_function function to notify of enable/disable * @param data data to pass to add_function and remove_function. * @param free_data_function function to be called to free the data. * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection *connection, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function) { dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); retval = _dbus_timeout_list_set_functions (connection->timeouts, add_function, remove_function, toggled_function, data, free_data_function); CONNECTION_UNLOCK (connection); return retval; } /** * Sets the mainloop wakeup function for the connection. This function * is responsible for waking up the main loop (if its sleeping in * another thread) when some some change has happened to the * connection that the mainloop needs to reconsider (e.g. a message * has been queued for writing). When using Qt, this typically * results in a call to QEventLoop::wakeUp(). When using GLib, it * would call g_main_context_wakeup(). * * @param connection the connection. * @param wakeup_main_function function to wake up the mainloop * @param data data to pass wakeup_main_function * @param free_data_function function to be called to free the data. */ void dbus_connection_set_wakeup_main_function (DBusConnection *connection, DBusWakeupMainFunction wakeup_main_function, void *data, DBusFreeFunction free_data_function) { void *old_data; DBusFreeFunction old_free_data; _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); old_data = connection->wakeup_main_data; old_free_data = connection->free_wakeup_main_data; connection->wakeup_main_function = wakeup_main_function; connection->wakeup_main_data = data; connection->free_wakeup_main_data = free_data_function; CONNECTION_UNLOCK (connection); /* Callback outside the lock */ if (old_free_data) (*old_free_data) (old_data); } /** * Set a function to be invoked when the dispatch status changes. * If the dispatch status is #DBUS_DISPATCH_DATA_REMAINS, then * dbus_connection_dispatch() needs to be called to process incoming * messages. However, dbus_connection_dispatch() MUST NOT BE CALLED * from inside the DBusDispatchStatusFunction. Indeed, almost * any reentrancy in this function is a bad idea. Instead, * the DBusDispatchStatusFunction should simply save an indication * that messages should be dispatched later, when the main loop * is re-entered. * * If you don't set a dispatch status function, you have to be sure to * dispatch on every iteration of your main loop, especially if * dbus_watch_handle() or dbus_timeout_handle() were called. * * @param connection the connection * @param function function to call on dispatch status changes * @param data data for function * @param free_data_function free the function data */ void dbus_connection_set_dispatch_status_function (DBusConnection *connection, DBusDispatchStatusFunction function, void *data, DBusFreeFunction free_data_function) { void *old_data; DBusFreeFunction old_free_data; _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); old_data = connection->dispatch_status_data; old_free_data = connection->free_dispatch_status_data; connection->dispatch_status_function = function; connection->dispatch_status_data = data; connection->free_dispatch_status_data = free_data_function; CONNECTION_UNLOCK (connection); /* Callback outside the lock */ if (old_free_data) (*old_free_data) (old_data); } /** * Get the UNIX file descriptor of the connection, if any. This can * be used for SELinux access control checks with getpeercon() for * example. DO NOT read or write to the file descriptor, or try to * select() on it; use DBusWatch for main loop integration. Not all * connections will have a file descriptor. So for adding descriptors * to the main loop, use dbus_watch_get_unix_fd() and so forth. * * If the connection is socket-based, you can also use * dbus_connection_get_socket(), which will work on Windows too. * This function always fails on Windows. * * Right now the returned descriptor is always a socket, but * that is not guaranteed. * * @param connection the connection * @param fd return location for the file descriptor. * @returns #TRUE if fd is successfully obtained. */ dbus_bool_t dbus_connection_get_unix_fd (DBusConnection *connection, int *fd) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (connection->transport != NULL, FALSE); #ifdef DBUS_WIN /* FIXME do this on a lower level */ return FALSE; #endif return dbus_connection_get_socket(connection, fd); } /** * Gets the underlying Windows or UNIX socket file descriptor * of the connection, if any. DO NOT read or write to the file descriptor, or try to * select() on it; use DBusWatch for main loop integration. Not all * connections will have a socket. So for adding descriptors * to the main loop, use dbus_watch_get_socket() and so forth. * * If the connection is not socket-based, this function will return FALSE, * even if the connection does have a file descriptor of some kind. * i.e. this function always returns specifically a socket file descriptor. * * @param connection the connection * @param fd return location for the file descriptor. * @returns #TRUE if fd is successfully obtained. */ dbus_bool_t dbus_connection_get_socket(DBusConnection *connection, int *fd) { dbus_bool_t retval; DBusSocket s = DBUS_SOCKET_INIT; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (connection->transport != NULL, FALSE); CONNECTION_LOCK (connection); retval = _dbus_transport_get_socket_fd (connection->transport, &s); if (retval) { *fd = _dbus_socket_get_int (s); } CONNECTION_UNLOCK (connection); return retval; } /** * Gets the UNIX user ID of the connection if known. Returns #TRUE if * the uid is filled in. Always returns #FALSE on non-UNIX platforms * for now, though in theory someone could hook Windows to NIS or * something. Always returns #FALSE prior to authenticating the * connection. * * The UID is only read by servers from clients; clients can't usually * get the UID of servers, because servers do not authenticate to * clients. The returned UID is the UID the connection authenticated * as. * * The message bus is a server and the apps connecting to the bus * are clients. * * You can ask the bus to tell you the UID of another connection though * if you like; this is done with dbus_bus_get_unix_user(). * * @param connection the connection * @param uid return location for the user ID * @returns #TRUE if uid is filled in with a valid user ID */ dbus_bool_t dbus_connection_get_unix_user (DBusConnection *connection, unsigned long *uid) { dbus_bool_t result; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (uid != NULL, FALSE); CONNECTION_LOCK (connection); if (!_dbus_transport_try_to_authenticate (connection->transport)) result = FALSE; else result = _dbus_transport_get_unix_user (connection->transport, uid); #ifdef DBUS_WIN _dbus_assert (!result); #endif CONNECTION_UNLOCK (connection); return result; } /** * Gets the process ID of the connection if any. * Returns #TRUE if the pid is filled in. * Always returns #FALSE prior to authenticating the * connection. * * @param connection the connection * @param pid return location for the process ID * @returns #TRUE if uid is filled in with a valid process ID */ dbus_bool_t dbus_connection_get_unix_process_id (DBusConnection *connection, unsigned long *pid) { dbus_bool_t result; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (pid != NULL, FALSE); CONNECTION_LOCK (connection); if (!_dbus_transport_try_to_authenticate (connection->transport)) result = FALSE; else result = _dbus_transport_get_unix_process_id (connection->transport, pid); CONNECTION_UNLOCK (connection); return result; } /** * Gets the ADT audit data of the connection if any. * Returns #TRUE if the structure pointer is returned. * Always returns #FALSE prior to authenticating the * connection. * * @param connection the connection * @param data return location for audit data * @param data_size return location for length of audit data * @returns #TRUE if audit data is filled in with a valid ucred pointer */ dbus_bool_t dbus_connection_get_adt_audit_session_data (DBusConnection *connection, void **data, dbus_int32_t *data_size) { dbus_bool_t result; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (data != NULL, FALSE); _dbus_return_val_if_fail (data_size != NULL, FALSE); CONNECTION_LOCK (connection); if (!_dbus_transport_try_to_authenticate (connection->transport)) result = FALSE; else result = _dbus_transport_get_adt_audit_session_data (connection->transport, data, data_size); CONNECTION_UNLOCK (connection); return result; } /** * Sets a predicate function used to determine whether a given user ID * is allowed to connect. When an incoming connection has * authenticated with a particular user ID, this function is called; * if it returns #TRUE, the connection is allowed to proceed, * otherwise the connection is disconnected. * * If the function is set to #NULL (as it is by default), then * only the same UID as the server process will be allowed to * connect. Also, root is always allowed to connect. * * On Windows, the function will be set and its free_data_function will * be invoked when the connection is freed or a new function is set. * However, the function will never be called, because there are * no UNIX user ids to pass to it, or at least none of the existing * auth protocols would allow authenticating as a UNIX user on Windows. * * @param connection the connection * @param function the predicate * @param data data to pass to the predicate * @param free_data_function function to free the data */ void dbus_connection_set_unix_user_function (DBusConnection *connection, DBusAllowUnixUserFunction function, void *data, DBusFreeFunction free_data_function) { void *old_data = NULL; DBusFreeFunction old_free_function = NULL; _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_unix_user_function (connection->transport, function, data, free_data_function, &old_data, &old_free_function); CONNECTION_UNLOCK (connection); if (old_free_function != NULL) (* old_free_function) (old_data); } /* Same calling convention as dbus_connection_get_windows_user */ dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection, char **label_p) { dbus_bool_t result; _dbus_assert (connection != NULL); _dbus_assert (label_p != NULL); CONNECTION_LOCK (connection); if (!_dbus_transport_try_to_authenticate (connection->transport)) result = FALSE; else result = _dbus_transport_get_linux_security_label (connection->transport, label_p); #ifndef __linux__ _dbus_assert (!result); #endif CONNECTION_UNLOCK (connection); return result; } /** * Gets the Windows user SID of the connection if known. Returns * #TRUE if the ID is filled in. Always returns #FALSE on non-Windows * platforms for now, though in theory someone could hook UNIX to * Active Directory or something. Always returns #FALSE prior to * authenticating the connection. * * The user is only read by servers from clients; clients can't usually * get the user of servers, because servers do not authenticate to * clients. The returned user is the user the connection authenticated * as. * * The message bus is a server and the apps connecting to the bus * are clients. * * The returned user string has to be freed with dbus_free(). * * The return value indicates whether the user SID is available; * if it's available but we don't have the memory to copy it, * then the return value is #TRUE and #NULL is given as the SID. * * @todo We would like to be able to say "You can ask the bus to tell * you the user of another connection though if you like; this is done * with dbus_bus_get_windows_user()." But this has to be implemented * in bus/driver.c and dbus/dbus-bus.c, and is pointless anyway * since on Windows we only use the session bus for now. * * @param connection the connection * @param windows_sid_p return location for an allocated copy of the user ID, or #NULL if no memory * @returns #TRUE if user is available (returned value may be #NULL anyway if no memory) */ dbus_bool_t dbus_connection_get_windows_user (DBusConnection *connection, char **windows_sid_p) { dbus_bool_t result; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (windows_sid_p != NULL, FALSE); CONNECTION_LOCK (connection); if (!_dbus_transport_try_to_authenticate (connection->transport)) result = FALSE; else result = _dbus_transport_get_windows_user (connection->transport, windows_sid_p); #ifdef DBUS_UNIX _dbus_assert (!result); #endif CONNECTION_UNLOCK (connection); return result; } /** * Sets a predicate function used to determine whether a given user ID * is allowed to connect. When an incoming connection has * authenticated with a particular user ID, this function is called; * if it returns #TRUE, the connection is allowed to proceed, * otherwise the connection is disconnected. * * If the function is set to #NULL (as it is by default), then * only the same user owning the server process will be allowed to * connect. * * On UNIX, the function will be set and its free_data_function will * be invoked when the connection is freed or a new function is set. * However, the function will never be called, because there is no * way right now to authenticate as a Windows user on UNIX. * * @param connection the connection * @param function the predicate * @param data data to pass to the predicate * @param free_data_function function to free the data */ void dbus_connection_set_windows_user_function (DBusConnection *connection, DBusAllowWindowsUserFunction function, void *data, DBusFreeFunction free_data_function) { void *old_data = NULL; DBusFreeFunction old_free_function = NULL; _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_windows_user_function (connection->transport, function, data, free_data_function, &old_data, &old_free_function); CONNECTION_UNLOCK (connection); if (old_free_function != NULL) (* old_free_function) (old_data); } /** * This function must be called on the server side of a connection when the * connection is first seen in the #DBusNewConnectionFunction. If set to * #TRUE (the default is #FALSE), then the connection can proceed even if * the client does not authenticate as some user identity, i.e. clients * can connect anonymously. * * This setting interacts with the available authorization mechanisms * (see dbus_server_set_auth_mechanisms()). Namely, an auth mechanism * such as ANONYMOUS that supports anonymous auth must be included in * the list of available mechanisms for anonymous login to work. * * This setting also changes the default rule for connections * authorized as a user; normally, if a connection authorizes as * a user identity, it is permitted if the user identity is * root or the user identity matches the user identity of the server * process. If anonymous connections are allowed, however, * then any user identity is allowed. * * You can override the rules for connections authorized as a * user identity with dbus_connection_set_unix_user_function() * and dbus_connection_set_windows_user_function(). * * @param connection the connection * @param value whether to allow authentication as an anonymous user */ void dbus_connection_set_allow_anonymous (DBusConnection *connection, dbus_bool_t value) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_allow_anonymous (connection->transport, value); CONNECTION_UNLOCK (connection); } /** * * Normally #DBusConnection automatically handles all messages to the * org.freedesktop.DBus.Peer interface. However, the message bus wants * to be able to route methods on that interface through the bus and * to other applications. If routing peer messages is enabled, then * messages with the org.freedesktop.DBus.Peer interface that also * have a bus destination name set will not be automatically * handled by the #DBusConnection and instead will be dispatched * normally to the application. * * If a normal application sets this flag, it can break things badly. * So don't set this unless you are the message bus. * * @param connection the connection * @param value #TRUE to pass through org.freedesktop.DBus.Peer messages with a bus name set */ void dbus_connection_set_route_peer_messages (DBusConnection *connection, dbus_bool_t value) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); connection->route_peer_messages = value; CONNECTION_UNLOCK (connection); } /** * Adds a message filter. Filters are handlers that are run on all * incoming messages, prior to the objects registered with * dbus_connection_register_object_path(). Filters are run in the * order that they were added. The same handler can be added as a * filter more than once, in which case it will be run more than once. * Filters added during a filter callback won't be run on the message * being processed. * * @todo we don't run filters on messages while blocking without * entering the main loop, since filters are run as part of * dbus_connection_dispatch(). This is probably a feature, as filters * could create arbitrary reentrancy. But kind of sucks if you're * trying to filter METHOD_RETURN for some reason. * * @param connection the connection * @param function function to handle messages * @param user_data user data to pass to the function * @param free_data_function function to use for freeing user data * @returns #TRUE on success, #FALSE if not enough memory. */ dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, DBusHandleMessageFunction function, void *user_data, DBusFreeFunction free_data_function) { DBusMessageFilter *filter; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (function != NULL, FALSE); filter = dbus_new0 (DBusMessageFilter, 1); if (filter == NULL) return FALSE; _dbus_atomic_inc (&filter->refcount); CONNECTION_LOCK (connection); if (!_dbus_list_append (&connection->filter_list, filter)) { _dbus_message_filter_unref (filter); CONNECTION_UNLOCK (connection); return FALSE; } /* Fill in filter after all memory allocated, * so we don't run the free_user_data_function * if the add_filter() fails */ filter->function = function; filter->user_data = user_data; filter->free_user_data_function = free_data_function; CONNECTION_UNLOCK (connection); return TRUE; } /** * Removes a previously-added message filter. It is a programming * error to call this function for a handler that has not been added * as a filter. If the given handler was added more than once, only * one instance of it will be removed (the most recently-added * instance). * * @param connection the connection * @param function the handler to remove * @param user_data user data for the handler to remove * */ void dbus_connection_remove_filter (DBusConnection *connection, DBusHandleMessageFunction function, void *user_data) { DBusList *link; DBusMessageFilter *filter; _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (function != NULL); CONNECTION_LOCK (connection); filter = NULL; link = _dbus_list_get_last_link (&connection->filter_list); while (link != NULL) { filter = link->data; if (filter->function == function && filter->user_data == user_data) { _dbus_list_remove_link (&connection->filter_list, link); filter->function = NULL; break; } link = _dbus_list_get_prev_link (&connection->filter_list, link); filter = NULL; } CONNECTION_UNLOCK (connection); #ifndef DBUS_DISABLE_CHECKS if (filter == NULL) { _dbus_warn_check_failed ("Attempt to remove filter function %p user data %p, but no such filter has been added\n", function, user_data); return; } #endif /* Call application code */ if (filter->free_user_data_function) (* filter->free_user_data_function) (filter->user_data); filter->free_user_data_function = NULL; filter->user_data = NULL; _dbus_message_filter_unref (filter); } /** * Registers a handler for a given path or subsection in the object * hierarchy. The given vtable handles messages sent to exactly the * given path or also for paths bellow that, depending on fallback * parameter. * * @param connection the connection * @param fallback whether to handle messages also for "subdirectory" * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ static dbus_bool_t _dbus_connection_register_object_path (DBusConnection *connection, dbus_bool_t fallback, const char *path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error) { char **decomposed_path; dbus_bool_t retval; if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) return FALSE; CONNECTION_LOCK (connection); retval = _dbus_object_tree_register (connection->objects, fallback, (const char **) decomposed_path, vtable, user_data, error); CONNECTION_UNLOCK (connection); dbus_free_string_array (decomposed_path); return retval; } /** * Registers a handler for a given path in the object hierarchy. * The given vtable handles messages sent to exactly the given path. * * @param connection the connection * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ dbus_bool_t dbus_connection_try_register_object_path (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); return _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, error); } /** * Registers a handler for a given path in the object hierarchy. * The given vtable handles messages sent to exactly the given path. * * It is a bug to call this function for object paths which already * have a handler. Use dbus_connection_try_register_object_path() if this * might be the case. * * @param connection the connection * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) ocurred */ dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data) { dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); retval = _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, &error); if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE)) { _dbus_warn ("%s\n", error.message); dbus_error_free (&error); return FALSE; } return retval; } /** * Registers a fallback handler for a given subsection of the object * hierarchy. The given vtable handles messages at or below the given * path. You can use this to establish a default message handling * policy for a whole "subdirectory." * * @param connection the connection * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ dbus_bool_t dbus_connection_try_register_fallback (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error) { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); return _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, error); } /** * Registers a fallback handler for a given subsection of the object * hierarchy. The given vtable handles messages at or below the given * path. You can use this to establish a default message handling * policy for a whole "subdirectory." * * It is a bug to call this function for object paths which already * have a handler. Use dbus_connection_try_register_fallback() if this * might be the case. * * @param connection the connection * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or * #DBUS_ERROR_OBJECT_PATH_IN_USE) occured */ dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data) { dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); retval = _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, &error); if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE)) { _dbus_warn ("%s\n", error.message); dbus_error_free (&error); return FALSE; } return retval; } /** * Unregisters the handler registered with exactly the given path. * It's a bug to call this function for a path that isn't registered. * Can unregister both fallback paths and object paths. * * @param connection the connection * @param path a '/' delimited string of path elements * @returns #FALSE if not enough memory */ dbus_bool_t dbus_connection_unregister_object_path (DBusConnection *connection, const char *path) { char **decomposed_path; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) return FALSE; CONNECTION_LOCK (connection); _dbus_object_tree_unregister_and_unlock (connection->objects, (const char **) decomposed_path); dbus_free_string_array (decomposed_path); return TRUE; } /** * Gets the user data passed to dbus_connection_register_object_path() * or dbus_connection_register_fallback(). If nothing was registered * at this path, the data is filled in with #NULL. * * @param connection the connection * @param path the path you registered with * @param data_p location to store the user data, or #NULL * @returns #FALSE if not enough memory */ dbus_bool_t dbus_connection_get_object_path_data (DBusConnection *connection, const char *path, void **data_p) { char **decomposed_path; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (data_p != NULL, FALSE); *data_p = NULL; if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) return FALSE; CONNECTION_LOCK (connection); *data_p = _dbus_object_tree_get_user_data_unlocked (connection->objects, (const char**) decomposed_path); CONNECTION_UNLOCK (connection); dbus_free_string_array (decomposed_path); return TRUE; } /** * Lists the registered fallback handlers and object path handlers at * the given parent_path. The returned array should be freed with * dbus_free_string_array(). * * @param connection the connection * @param parent_path the path to list the child handlers of * @param child_entries returns #NULL-terminated array of children * @returns #FALSE if no memory to allocate the child entries */ dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, const char *parent_path, char ***child_entries) { char **decomposed_path; dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (parent_path != NULL, FALSE); _dbus_return_val_if_fail (parent_path[0] == '/', FALSE); _dbus_return_val_if_fail (child_entries != NULL, FALSE); if (!_dbus_decompose_path (parent_path, strlen (parent_path), &decomposed_path, NULL)) return FALSE; CONNECTION_LOCK (connection); retval = _dbus_object_tree_list_registered_and_unlock (connection->objects, (const char **) decomposed_path, child_entries); dbus_free_string_array (decomposed_path); return retval; } static DBusDataSlotAllocator slot_allocator = _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (connection_slots)); /** * Allocates an integer ID to be used for storing application-specific * data on any DBusConnection. The allocated ID may then be used * with dbus_connection_set_data() and dbus_connection_get_data(). * The passed-in slot must be initialized to -1, and is filled in * with the slot ID. If the passed-in slot is not -1, it's assumed * to be already allocated, and its refcount is incremented. * * The allocated slot is global, i.e. all DBusConnection objects will * have a slot with the given integer ID reserved. * * @param slot_p address of a global variable storing the slot * @returns #FALSE on failure (no memory) */ dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p) { return _dbus_data_slot_allocator_alloc (&slot_allocator, slot_p); } /** * Deallocates a global ID for connection data slots. * dbus_connection_get_data() and dbus_connection_set_data() may no * longer be used with this slot. Existing data stored on existing * DBusConnection objects will be freed when the connection is * finalized, but may not be retrieved (and may only be replaced if * someone else reallocates the slot). When the refcount on the * passed-in slot reaches 0, it is set to -1. * * @param slot_p address storing the slot to deallocate */ void dbus_connection_free_data_slot (dbus_int32_t *slot_p) { _dbus_return_if_fail (*slot_p >= 0); _dbus_data_slot_allocator_free (&slot_allocator, slot_p); } /** * Stores a pointer on a DBusConnection, along * with an optional function to be used for freeing * the data when the data is set again, or when * the connection is finalized. The slot number * must have been allocated with dbus_connection_allocate_data_slot(). * * @note This function does not take the * main thread lock on DBusConnection, which allows it to be * used from inside watch and timeout functions. (See the * note in docs for dbus_connection_set_watch_functions().) * A side effect of this is that you need to know there's * a reference held on the connection while invoking * dbus_connection_set_data(), or the connection could be * finalized during dbus_connection_set_data(). * * @param connection the connection * @param slot the slot number * @param data the data to store * @param free_data_func finalizer function for the data * @returns #TRUE if there was enough memory to store the data */ dbus_bool_t dbus_connection_set_data (DBusConnection *connection, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func) { DBusFreeFunction old_free_func; void *old_data; dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (slot >= 0, FALSE); SLOTS_LOCK (connection); retval = _dbus_data_slot_list_set (&slot_allocator, &connection->slot_list, slot, data, free_data_func, &old_free_func, &old_data); SLOTS_UNLOCK (connection); if (retval) { /* Do the actual free outside the connection lock */ if (old_free_func) (* old_free_func) (old_data); } return retval; } /** * Retrieves data previously set with dbus_connection_set_data(). * The slot must still be allocated (must not have been freed). * * @note This function does not take the * main thread lock on DBusConnection, which allows it to be * used from inside watch and timeout functions. (See the * note in docs for dbus_connection_set_watch_functions().) * A side effect of this is that you need to know there's * a reference held on the connection while invoking * dbus_connection_get_data(), or the connection could be * finalized during dbus_connection_get_data(). * * @param connection the connection * @param slot the slot to get data from * @returns the data, or #NULL if not found */ void* dbus_connection_get_data (DBusConnection *connection, dbus_int32_t slot) { void *res; _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_fail (slot >= 0, NULL); SLOTS_LOCK (connection); res = _dbus_data_slot_list_get (&slot_allocator, &connection->slot_list, slot); SLOTS_UNLOCK (connection); return res; } /** * This function sets a global flag for whether dbus_connection_new() * will set SIGPIPE behavior to SIG_IGN. * * @param will_modify_sigpipe #TRUE to allow sigpipe to be set to SIG_IGN */ void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe) { _dbus_modify_sigpipe = will_modify_sigpipe != FALSE; } /** * Specifies the maximum size message this connection is allowed to * receive. Larger messages will result in disconnecting the * connection. * * @param connection a #DBusConnection * @param size maximum message size the connection can receive, in bytes */ void dbus_connection_set_max_message_size (DBusConnection *connection, long size) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_max_message_size (connection->transport, size); CONNECTION_UNLOCK (connection); } /** * Gets the value set by dbus_connection_set_max_message_size(). * * @param connection the connection * @returns the max size of a single message */ long dbus_connection_get_max_message_size (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_transport_get_max_message_size (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Specifies the maximum number of unix fds a message on this * connection is allowed to receive. Messages with more unix fds will * result in disconnecting the connection. * * @param connection a #DBusConnection * @param n maximum message unix fds the connection can receive */ void dbus_connection_set_max_message_unix_fds (DBusConnection *connection, long n) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_max_message_unix_fds (connection->transport, n); CONNECTION_UNLOCK (connection); } /** * Gets the value set by dbus_connection_set_max_message_unix_fds(). * * @param connection the connection * @returns the max numer of unix fds of a single message */ long dbus_connection_get_max_message_unix_fds (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_transport_get_max_message_unix_fds (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Sets the maximum total number of bytes that can be used for all messages * received on this connection. Messages count toward the maximum until * they are finalized. When the maximum is reached, the connection will * not read more data until some messages are finalized. * * The semantics of the maximum are: if outstanding messages are * already above the maximum, additional messages will not be read. * The semantics are not: if the next message would cause us to exceed * the maximum, we don't read it. The reason is that we don't know the * size of a message until after we read it. * * Thus, the max live messages size can actually be exceeded * by up to the maximum size of a single message. * * Also, if we read say 1024 bytes off the wire in a single read(), * and that contains a half-dozen small messages, we may exceed the * size max by that amount. But this should be inconsequential. * * This does imply that we can't call read() with a buffer larger * than we're willing to exceed this limit by. * * @param connection the connection * @param size the maximum size in bytes of all outstanding messages */ void dbus_connection_set_max_received_size (DBusConnection *connection, long size) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_max_received_size (connection->transport, size); CONNECTION_UNLOCK (connection); } /** * Gets the value set by dbus_connection_set_max_received_size(). * * @param connection the connection * @returns the max size of all live messages */ long dbus_connection_get_max_received_size (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_transport_get_max_received_size (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Sets the maximum total number of unix fds that can be used for all messages * received on this connection. Messages count toward the maximum until * they are finalized. When the maximum is reached, the connection will * not read more data until some messages are finalized. * * The semantics are analogous to those of dbus_connection_set_max_received_size(). * * @param connection the connection * @param n the maximum size in bytes of all outstanding messages */ void dbus_connection_set_max_received_unix_fds (DBusConnection *connection, long n) { _dbus_return_if_fail (connection != NULL); CONNECTION_LOCK (connection); _dbus_transport_set_max_received_unix_fds (connection->transport, n); CONNECTION_UNLOCK (connection); } /** * Gets the value set by dbus_connection_set_max_received_unix_fds(). * * @param connection the connection * @returns the max unix fds of all live messages */ long dbus_connection_get_max_received_unix_fds (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_transport_get_max_received_unix_fds (connection->transport); CONNECTION_UNLOCK (connection); return res; } /** * Gets the approximate size in bytes of all messages in the outgoing * message queue. The size is approximate in that you shouldn't use * it to decide how many bytes to read off the network or anything * of that nature, as optimizations may choose to tell small white lies * to avoid performance overhead. * * @param connection the connection * @returns the number of bytes that have been queued up but not sent */ long dbus_connection_get_outgoing_size (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_counter_get_size_value (connection->outgoing_counter); CONNECTION_UNLOCK (connection); return res; } #ifdef DBUS_ENABLE_STATS void _dbus_connection_get_stats (DBusConnection *connection, dbus_uint32_t *in_messages, dbus_uint32_t *in_bytes, dbus_uint32_t *in_fds, dbus_uint32_t *in_peak_bytes, dbus_uint32_t *in_peak_fds, dbus_uint32_t *out_messages, dbus_uint32_t *out_bytes, dbus_uint32_t *out_fds, dbus_uint32_t *out_peak_bytes, dbus_uint32_t *out_peak_fds) { CONNECTION_LOCK (connection); if (in_messages != NULL) *in_messages = connection->n_incoming; _dbus_transport_get_stats (connection->transport, in_bytes, in_fds, in_peak_bytes, in_peak_fds); if (out_messages != NULL) *out_messages = connection->n_outgoing; if (out_bytes != NULL) *out_bytes = _dbus_counter_get_size_value (connection->outgoing_counter); if (out_fds != NULL) *out_fds = _dbus_counter_get_unix_fd_value (connection->outgoing_counter); if (out_peak_bytes != NULL) *out_peak_bytes = _dbus_counter_get_peak_size_value (connection->outgoing_counter); if (out_peak_fds != NULL) *out_peak_fds = _dbus_counter_get_peak_unix_fd_value (connection->outgoing_counter); CONNECTION_UNLOCK (connection); } #endif /* DBUS_ENABLE_STATS */ /** * Gets the approximate number of uni fds of all messages in the * outgoing message queue. * * @param connection the connection * @returns the number of unix fds that have been queued up but not sent */ long dbus_connection_get_outgoing_unix_fds (DBusConnection *connection) { long res; _dbus_return_val_if_fail (connection != NULL, 0); CONNECTION_LOCK (connection); res = _dbus_counter_get_unix_fd_value (connection->outgoing_counter); CONNECTION_UNLOCK (connection); return res; } #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Returns the address of the transport object of this connection * * @param connection the connection * @returns the address string */ const char* _dbus_connection_get_address (DBusConnection *connection) { return _dbus_transport_get_address (connection->transport); } #endif /** @} */ dbus-1.10.6/dbus/dbus-bus.c0000644000175000017500000014407112602773110015371 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-bus.c Convenience functions for communicating with the bus. * * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-bus.h" #include "dbus-protocol.h" #include "dbus-internals.h" #include "dbus-message.h" #include "dbus-marshal-validate.h" #include "dbus-misc.h" #include "dbus-threads-internal.h" #include "dbus-connection-internal.h" #include "dbus-string.h" /** * @defgroup DBusBus Message bus APIs * @ingroup DBus * @brief Functions for communicating with the message bus * * dbus_bus_get() allows all modules and libraries in a given * process to share the same connection to the bus daemon by storing * the connection globally. * * All other functions in this module are just convenience functions; * most of them invoke methods on the bus daemon, by sending method * call messages to #DBUS_SERVICE_DBUS. These convenience functions * often make blocking method calls. If you don't want to block, * you can send the method call messages manually in the same way * you would any other method call message. * * This module is the only one in libdbus that's specific to * communicating with the message bus daemon. The rest of the API can * also be used for connecting to another application directly. * * @todo right now the default address of the system bus is hardcoded, * so if you change it in the global config file suddenly you have to * set DBUS_SYSTEM_BUS_ADDRESS env variable. Might be nice if the * client lib somehow read the config file, or if the bus on startup * somehow wrote out its address to a well-known spot, but might also * not be worth it. */ /** * @defgroup DBusBusInternals Message bus APIs internals * @ingroup DBusInternals * @brief Internals of functions for communicating with the message bus * * @{ */ /** * Block of message-bus-related data we attach to each * #DBusConnection used with these convenience functions. * */ typedef struct { DBusConnection *connection; /**< Connection we're associated with */ char *unique_name; /**< Unique name of this connection */ unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */ } BusData; /** The slot we have reserved to store BusData. */ static dbus_int32_t bus_data_slot = -1; /** Number of bus types */ #define N_BUS_TYPES 3 static DBusConnection *bus_connections[N_BUS_TYPES]; static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL }; static DBusBusType activation_bus_type = DBUS_BUS_STARTER; static dbus_bool_t initialized = FALSE; static void addresses_shutdown_func (void *data) { int i; i = 0; while (i < N_BUS_TYPES) { if (bus_connections[i] != NULL) _dbus_warn_check_failed ("dbus_shutdown() called but connections were still live. This probably means the application did not drop all its references to bus connections.\n"); dbus_free (bus_connection_addresses[i]); bus_connection_addresses[i] = NULL; ++i; } activation_bus_type = DBUS_BUS_STARTER; initialized = FALSE; } static dbus_bool_t get_from_env (char **connection_p, const char *env_var) { const char *s; _dbus_assert (*connection_p == NULL); s = _dbus_getenv (env_var); if (s == NULL || *s == '\0') return TRUE; /* successfully didn't use the env var */ else { *connection_p = _dbus_strdup (s); return *connection_p != NULL; } } static dbus_bool_t init_session_address (void) { dbus_bool_t retval; retval = FALSE; /* First, look in the environment. This is the normal case on * freedesktop.org/Unix systems. */ get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], "DBUS_SESSION_BUS_ADDRESS"); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) { dbus_bool_t supported; DBusString addr; DBusError error = DBUS_ERROR_INIT; if (!_dbus_string_init (&addr)) return FALSE; supported = FALSE; /* So it's not in the environment - let's try a platform-specific method. * On MacOS, this involves asking launchd. On Windows (not specified yet) * we might do a COM lookup. * Ignore errors - if we failed, fall back to autolaunch. */ retval = _dbus_lookup_session_address (&supported, &addr, &error); if (supported && retval) { retval =_dbus_string_steal_data (&addr, &bus_connection_addresses[DBUS_BUS_SESSION]); } else if (supported && !retval) { if (dbus_error_is_set(&error)) _dbus_warn ("Dynamic session lookup supported but failed: %s\n", error.message); else _dbus_warn ("Dynamic session lookup supported but failed silently\n"); } _dbus_string_free (&addr); } else retval = TRUE; if (!retval) return FALSE; /* We have a hard-coded (but compile-time-configurable) fallback address for * the session bus. */ if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) bus_connection_addresses[DBUS_BUS_SESSION] = _dbus_strdup (DBUS_SESSION_BUS_CONNECT_ADDRESS); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) return FALSE; return TRUE; } static dbus_bool_t init_connections_unlocked (void) { if (!initialized) { const char *s; int i; i = 0; while (i < N_BUS_TYPES) { bus_connections[i] = NULL; ++i; } /* Don't init these twice, we may run this code twice if * init_connections_unlocked() fails midway through. * In practice, each block below should contain only one * "return FALSE" or running through twice may not * work right. */ if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) { _dbus_verbose ("Filling in system bus address...\n"); if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM], "DBUS_SYSTEM_BUS_ADDRESS")) return FALSE; } if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) { /* Use default system bus address if none set in environment */ bus_connection_addresses[DBUS_BUS_SYSTEM] = _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS); if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) return FALSE; _dbus_verbose (" used default system bus \"%s\"\n", bus_connection_addresses[DBUS_BUS_SYSTEM]); } else _dbus_verbose (" used env var system bus \"%s\"\n", bus_connection_addresses[DBUS_BUS_SYSTEM]); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) { _dbus_verbose ("Filling in session bus address...\n"); if (!init_session_address ()) return FALSE; _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ? bus_connection_addresses[DBUS_BUS_SESSION] : "none set"); } if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) { _dbus_verbose ("Filling in activation bus address...\n"); if (!get_from_env (&bus_connection_addresses[DBUS_BUS_STARTER], "DBUS_STARTER_ADDRESS")) return FALSE; _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_STARTER] ? bus_connection_addresses[DBUS_BUS_STARTER] : "none set"); } if (bus_connection_addresses[DBUS_BUS_STARTER] != NULL) { s = _dbus_getenv ("DBUS_STARTER_BUS_TYPE"); if (s != NULL) { _dbus_verbose ("Bus activation type was set to \"%s\"\n", s); if (strcmp (s, "system") == 0) activation_bus_type = DBUS_BUS_SYSTEM; else if (strcmp (s, "session") == 0) activation_bus_type = DBUS_BUS_SESSION; } } else { /* Default to the session bus instead if available */ if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL) { bus_connection_addresses[DBUS_BUS_STARTER] = _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]); if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) return FALSE; } } /* If we return FALSE we have to be sure that restarting * the above code will work right */ if (!_dbus_register_shutdown_func (addresses_shutdown_func, NULL)) return FALSE; initialized = TRUE; } return initialized; } static void bus_data_free (void *data) { BusData *bd = data; if (bd->is_well_known) { int i; if (!_DBUS_LOCK (bus)) _dbus_assert_not_reached ("global locks should have been initialized " "when we attached bus data"); /* We may be stored in more than one slot */ /* This should now be impossible - these slots are supposed to * be cleared on disconnect, so should not need to be cleared on * finalize */ i = 0; while (i < N_BUS_TYPES) { if (bus_connections[i] == bd->connection) bus_connections[i] = NULL; ++i; } _DBUS_UNLOCK (bus); } dbus_free (bd->unique_name); dbus_free (bd); dbus_connection_free_data_slot (&bus_data_slot); } static BusData* ensure_bus_data (DBusConnection *connection) { BusData *bd; if (!dbus_connection_allocate_data_slot (&bus_data_slot)) return NULL; bd = dbus_connection_get_data (connection, bus_data_slot); if (bd == NULL) { bd = dbus_new0 (BusData, 1); if (bd == NULL) { dbus_connection_free_data_slot (&bus_data_slot); return NULL; } bd->connection = connection; if (!dbus_connection_set_data (connection, bus_data_slot, bd, bus_data_free)) { dbus_free (bd); dbus_connection_free_data_slot (&bus_data_slot); return NULL; } /* Data slot refcount now held by the BusData */ } else { dbus_connection_free_data_slot (&bus_data_slot); } return bd; } /** * Internal function that checks to see if this * is a shared connection owned by the bus and if it is unref it. * * @param connection a connection that has been disconnected. */ void _dbus_bus_notify_shared_connection_disconnected_unlocked (DBusConnection *connection) { int i; if (!_DBUS_LOCK (bus)) { /* If it was in bus_connections, we would have initialized global locks * when we added it. So, it can't be. */ return; } /* We are expecting to have the connection saved in only one of these * slots, but someone could in a pathological case set system and session * bus to the same bus or something. Or set one of them to the starter * bus without setting the starter bus type in the env variable. * So we don't break the loop as soon as we find a match. */ for (i = 0; i < N_BUS_TYPES; ++i) { if (bus_connections[i] == connection) { bus_connections[i] = NULL; } } _DBUS_UNLOCK (bus); } static DBusConnection * internal_bus_get (DBusBusType type, dbus_bool_t private, DBusError *error) { const char *address; DBusConnection *connection; BusData *bd; DBusBusType address_type; _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL); _dbus_return_val_if_error_is_set (error, NULL); connection = NULL; if (!_DBUS_LOCK (bus)) { _DBUS_SET_OOM (error); /* do not "goto out", that would try to unlock */ return NULL; } if (!init_connections_unlocked ()) { _DBUS_SET_OOM (error); goto out; } /* We want to use the activation address even if the * activating bus is the session or system bus, * per the spec. */ address_type = type; /* Use the real type of the activation bus for getting its * connection, but only if the real type's address is available. (If * the activating bus isn't a well-known bus then * activation_bus_type == DBUS_BUS_STARTER) */ if (type == DBUS_BUS_STARTER && bus_connection_addresses[activation_bus_type] != NULL) type = activation_bus_type; if (!private && bus_connections[type] != NULL) { connection = bus_connections[type]; dbus_connection_ref (connection); goto out; } address = bus_connection_addresses[address_type]; if (address == NULL) { dbus_set_error (error, DBUS_ERROR_FAILED, "Unable to determine the address of the message bus (try 'man dbus-launch' and 'man dbus-daemon' for help)"); goto out; } if (private) connection = dbus_connection_open_private (address, error); else connection = dbus_connection_open (address, error); if (!connection) { goto out; } if (!dbus_bus_register (connection, error)) { _dbus_connection_close_possibly_shared (connection); dbus_connection_unref (connection); connection = NULL; goto out; } if (!private) { /* store a weak ref to the connection (dbus-connection.c is * supposed to have a strong ref that it drops on disconnect, * since this is a shared connection) */ bus_connections[type] = connection; } /* By default we're bound to the lifecycle of * the message bus. */ dbus_connection_set_exit_on_disconnect (connection, TRUE); if (!_DBUS_LOCK (bus_datas)) _dbus_assert_not_reached ("global locks were initialized already"); bd = ensure_bus_data (connection); _dbus_assert (bd != NULL); /* it should have been created on register, so OOM not possible */ bd->is_well_known = TRUE; _DBUS_UNLOCK (bus_datas); out: /* Return a reference to the caller, or NULL with error set. */ if (connection == NULL) _DBUS_ASSERT_ERROR_IS_SET (error); _DBUS_UNLOCK (bus); return connection; } /** @} */ /* end of implementation details docs */ /** * @addtogroup DBusBus * @{ */ /** * Connects to a bus daemon and registers the client with it. If a * connection to the bus already exists, then that connection is * returned. The caller of this function owns a reference to the bus. * * The caller may NOT call dbus_connection_close() on this connection; * see dbus_connection_open() and dbus_connection_close() for details * on that. * * If this function obtains a new connection object never before * returned from dbus_bus_get(), it will call * dbus_connection_set_exit_on_disconnect(), so the application * will exit if the connection closes. You can undo this * by calling dbus_connection_set_exit_on_disconnect() yourself * after you get the connection. * * dbus_bus_get() calls dbus_bus_register() for you. * * If returning a newly-created connection, this function will block * until authentication and bus registration are complete. * * @param type bus type * @param error address where an error can be returned. * @returns a #DBusConnection with new ref or #NULL on error */ DBusConnection * dbus_bus_get (DBusBusType type, DBusError *error) { return internal_bus_get (type, FALSE, error); } /** * Connects to a bus daemon and registers the client with it as with * dbus_bus_register(). Unlike dbus_bus_get(), always creates a new * connection. This connection will not be saved or recycled by * libdbus. Caller owns a reference to the bus and must either close * it or know it to be closed prior to releasing this reference. * * See dbus_connection_open_private() for more details on when to * close and unref this connection. * * This function calls * dbus_connection_set_exit_on_disconnect() on the new connection, so the application * will exit if the connection closes. You can undo this * by calling dbus_connection_set_exit_on_disconnect() yourself * after you get the connection. * * dbus_bus_get_private() calls dbus_bus_register() for you. * * This function will block until authentication and bus registration * are complete. * * @param type bus type * @param error address where an error can be returned. * @returns a DBusConnection with new ref */ DBusConnection * dbus_bus_get_private (DBusBusType type, DBusError *error) { return internal_bus_get (type, TRUE, error); } /** * Registers a connection with the bus. This must be the first * thing an application does when connecting to the message bus. * If registration succeeds, the unique name will be set, * and can be obtained using dbus_bus_get_unique_name(). * * This function will block until registration is complete. * * If the connection has already registered with the bus * (determined by checking whether dbus_bus_get_unique_name() * returns a non-#NULL value), then this function does nothing. * * If you use dbus_bus_get() or dbus_bus_get_private() this * function will be called for you. * * @note Just use dbus_bus_get() or dbus_bus_get_private() instead of * dbus_bus_register() and save yourself some pain. Using * dbus_bus_register() manually is only useful if you have your * own custom message bus not found in #DBusBusType. * * If you open a bus connection with dbus_connection_open() or * dbus_connection_open_private() you will have to dbus_bus_register() * yourself, or make the appropriate registration method calls * yourself. If you send the method calls yourself, call * dbus_bus_set_unique_name() with the unique bus name you get from * the bus. * * For shared connections (created with dbus_connection_open()) in a * multithreaded application, you can't really make the registration * calls yourself, because you don't know whether some other thread is * also registering, and the bus will kick you off if you send two * registration messages. * * If you use dbus_bus_register() however, there is a lock that * keeps both apps from registering at the same time. * * The rule in a multithreaded app, then, is that dbus_bus_register() * must be used to register, or you need to have your own locks that * all threads in the app will respect. * * In a single-threaded application you can register by hand instead * of using dbus_bus_register(), as long as you check * dbus_bus_get_unique_name() to see if a unique name has already been * stored by another thread before you send the registration messages. * * @param connection the connection * @param error place to store errors * @returns #TRUE on success */ dbus_bool_t dbus_bus_register (DBusConnection *connection, DBusError *error) { DBusMessage *message, *reply; char *name; BusData *bd; dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); retval = FALSE; message = NULL; reply = NULL; if (!_DBUS_LOCK (bus_datas)) { _DBUS_SET_OOM (error); /* do not "goto out", that would try to unlock */ return FALSE; } bd = ensure_bus_data (connection); if (bd == NULL) { _DBUS_SET_OOM (error); goto out; } if (bd->unique_name != NULL) { _dbus_verbose ("Ignoring attempt to register the same DBusConnection %s with the message bus a second time.\n", bd->unique_name); /* Success! */ retval = TRUE; goto out; } message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "Hello"); if (!message) { _DBUS_SET_OOM (error); goto out; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); if (reply == NULL) goto out; else if (dbus_set_error_from_message (error, reply)) goto out; else if (!dbus_message_get_args (reply, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) goto out; bd->unique_name = _dbus_strdup (name); if (bd->unique_name == NULL) { _DBUS_SET_OOM (error); goto out; } retval = TRUE; out: _DBUS_UNLOCK (bus_datas); if (message) dbus_message_unref (message); if (reply) dbus_message_unref (reply); if (!retval) _DBUS_ASSERT_ERROR_IS_SET (error); return retval; } /** * Sets the unique name of the connection, as assigned by the message * bus. Can only be used if you registered with the bus manually * (i.e. if you did not call dbus_bus_register()). Can only be called * once per connection. After the unique name is set, you can get it * with dbus_bus_get_unique_name(). * * The only reason to use this function is to re-implement the * equivalent of dbus_bus_register() yourself. One (probably unusual) * reason to do that might be to do the bus registration call * asynchronously instead of synchronously. * * @note Just use dbus_bus_get() or dbus_bus_get_private(), or worst * case dbus_bus_register(), instead of messing with this * function. There's really no point creating pain for yourself by * doing things manually. * * It's hard to use this function safely on shared connections * (created by dbus_connection_open()) in a multithreaded application, * because only one registration attempt can be sent to the bus. If * two threads are both sending the registration message, there is no * mechanism in libdbus itself to avoid sending it twice. * * Thus, you need a way to coordinate which thread sends the * registration attempt; which also means you know which thread * will call dbus_bus_set_unique_name(). If you don't know * about all threads in the app (for example, if some libraries * you're using might start libdbus-using threads), then you * need to avoid using this function on shared connections. * * @param connection the connection * @param unique_name the unique name * @returns #FALSE if not enough memory */ dbus_bool_t dbus_bus_set_unique_name (DBusConnection *connection, const char *unique_name) { BusData *bd; dbus_bool_t success = FALSE; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (unique_name != NULL, FALSE); if (!_DBUS_LOCK (bus_datas)) { /* do not "goto out", that would try to unlock */ return FALSE; } bd = ensure_bus_data (connection); if (bd == NULL) goto out; _dbus_assert (bd->unique_name == NULL); bd->unique_name = _dbus_strdup (unique_name); success = bd->unique_name != NULL; out: _DBUS_UNLOCK (bus_datas); return success; } /** * Gets the unique name of the connection as assigned by the message * bus. Only possible after the connection has been registered with * the message bus. All connections returned by dbus_bus_get() or * dbus_bus_get_private() have been successfully registered. * * The name remains valid until the connection is freed, and * should not be freed by the caller. * * Other than dbus_bus_get(), there are two ways to set the unique * name; one is dbus_bus_register(), the other is * dbus_bus_set_unique_name(). You are responsible for calling * dbus_bus_set_unique_name() if you register by hand instead of using * dbus_bus_register(). * * @param connection the connection * @returns the unique name or #NULL on error */ const char* dbus_bus_get_unique_name (DBusConnection *connection) { BusData *bd; const char *unique_name = NULL; _dbus_return_val_if_fail (connection != NULL, NULL); if (!_DBUS_LOCK (bus_datas)) { /* We'd have initialized locks when we gave it its unique name, if it * had one. Don't "goto out", that would try to unlock. */ return NULL; } bd = ensure_bus_data (connection); if (bd == NULL) goto out; unique_name = bd->unique_name; out: _DBUS_UNLOCK (bus_datas); return unique_name; } /** * Asks the bus to return the UID the named connection authenticated * as, if any. Only works on UNIX; only works for connections on the * same machine as the bus. If you are not on the same machine as the * bus, then calling this is probably a bad idea, since the UID will * mean little to your application. * * For the system message bus you're guaranteed to be on the same * machine since it only listens on a UNIX domain socket (at least, * as shipped by default). * * This function only works for connections that authenticated as * a UNIX user, right now that includes all bus connections, but * it's very possible to have connections with no associated UID. * So check for errors and do something sensible if they happen. * * This function will always return an error on Windows. * * @param connection the connection * @param name a name owned by the connection * @param error location to store the error * @returns the unix user id, or ((unsigned)-1) if error is set */ unsigned long dbus_bus_get_unix_user (DBusConnection *connection, const char *name, DBusError *error) { DBusMessage *message, *reply; dbus_uint32_t uid; _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET); _dbus_return_val_if_fail (name != NULL, DBUS_UID_UNSET); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), DBUS_UID_UNSET); _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixUser"); if (message == NULL) { _DBUS_SET_OOM (error); return DBUS_UID_UNSET; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return DBUS_UID_UNSET; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_UID_UNSET; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return DBUS_UID_UNSET; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return DBUS_UID_UNSET; } dbus_message_unref (reply); return (unsigned long) uid; } /** * Asks the bus to return its globally unique ID, as described in the * D-Bus specification. For the session bus, this is useful as a way * to uniquely identify each user session. For the system bus, * probably the bus ID is not useful; instead, use the machine ID * since it's accessible without necessarily connecting to the bus and * may be persistent beyond a single bus instance (across reboots for * example). See dbus_get_local_machine_id(). * * In addition to an ID for each bus and an ID for each machine, there is * an ID for each address that the bus is listening on; that can * be retrieved with dbus_connection_get_server_id(), though it is * probably not very useful. * * @param connection the connection * @param error location to store the error * @returns the bus ID or #NULL if error is set */ char* dbus_bus_get_id (DBusConnection *connection, DBusError *error) { DBusMessage *message, *reply; char *id; const char *v_STRING; _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetId"); if (message == NULL) { _DBUS_SET_OOM (error); return NULL; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return NULL; } v_STRING = NULL; if (!dbus_message_get_args (reply, error, DBUS_TYPE_STRING, &v_STRING, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return NULL; } id = _dbus_strdup (v_STRING); /* may be NULL */ dbus_message_unref (reply); if (id == NULL) _DBUS_SET_OOM (error); /* FIXME it might be nice to cache the ID locally */ return id; } /** * Asks the bus to assign the given name to this connection by invoking * the RequestName method on the bus. This method is fully documented * in the D-Bus specification. For quick reference, the flags and * result codes are discussed here, but the specification is the * canonical version of this information. * * First you should know that for each bus name, the bus stores * a queue of connections that would like to own it. Only * one owns it at a time - called the primary owner. If the primary * owner releases the name or disconnects, then the next owner in the * queue atomically takes over. * * So for example if you have an application org.freedesktop.TextEditor * and multiple instances of it can be run, you can have all of them * sitting in the queue. The first one to start up will receive messages * sent to org.freedesktop.TextEditor, but if that one exits another * will become the primary owner and receive messages. * * The queue means you don't need to manually watch for the current owner to * disappear and then request the name again. * * When requesting a name, you can specify several flags. * * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT and #DBUS_NAME_FLAG_DO_NOT_QUEUE * are properties stored by the bus for this connection with respect to * each requested bus name. These properties are stored even if the * connection is queued and does not become the primary owner. * You can update these flags by calling RequestName again (even if * you already own the name). * * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT means that another requestor of the * name can take it away from you by specifying #DBUS_NAME_FLAG_REPLACE_EXISTING. * * #DBUS_NAME_FLAG_DO_NOT_QUEUE means that if you aren't the primary owner, * you don't want to be queued up - you only care about being the * primary owner. * * Unlike the other two flags, #DBUS_NAME_FLAG_REPLACE_EXISTING is a property * of the individual RequestName call, i.e. the bus does not persistently * associate it with the connection-name pair. If a RequestName call includes * the #DBUS_NAME_FLAG_REPLACE_EXISTING flag, and the current primary * owner has #DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, then the current primary * owner will be kicked off. * * If no flags are given, an application will receive the requested * name only if the name is currently unowned; and it will NOT give * up the name if another application asks to take it over using * #DBUS_NAME_FLAG_REPLACE_EXISTING. * * This function returns a result code. The possible result codes * are as follows. * * #DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER means that the name had no * existing owner, and the caller is now the primary owner; or that * the name had an owner, and the caller specified * #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner * specified #DBUS_NAME_FLAG_ALLOW_REPLACEMENT. * * #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the caller does NOT * specify #DBUS_NAME_FLAG_DO_NOT_QUEUE and either the current owner * did NOT specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT * specify #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up * in a queue to own the name after the current owner gives it up. * * #DBUS_REQUEST_NAME_REPLY_EXISTS happens if the name has an owner * already and the caller specifies #DBUS_NAME_FLAG_DO_NOT_QUEUE * and either the current owner has NOT specified * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT specify * #DBUS_NAME_FLAG_REPLACE_EXISTING. * * #DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER happens if an application * requests a name it already owns. (Re-requesting a name is useful if * you want to change the #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or * #DBUS_NAME_FLAG_DO_NOT_QUEUE settings.) * * When a service represents an application, say "text editor," then * it should specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT if it wants * the last editor started to be the user's editor vs. the first one * started. Then any editor that can be the user's editor should * specify #DBUS_NAME_FLAG_REPLACE_EXISTING to either take over * (last-started-wins) or be queued up (first-started-wins) according * to whether #DBUS_NAME_FLAG_ALLOW_REPLACEMENT was given. * * Conventionally, single-instance applications often offer a command * line option called --replace which means to replace the current * instance. To implement this, always set * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT when you request your * application's bus name. When you lose ownership of your bus name, * you need to exit. Look for the signal "NameLost" from * #DBUS_SERVICE_DBUS and #DBUS_INTERFACE_DBUS (the signal's first * argument is the bus name that was lost). If starting up without * --replace, do not specify #DBUS_NAME_FLAG_REPLACE_EXISTING, and * exit if you fail to become the bus name owner. If --replace is * given, ask to replace the old owner. * * @param connection the connection * @param name the name to request * @param flags flags * @param error location to store the error * @returns a result code, -1 if error is set */ int dbus_bus_request_name (DBusConnection *connection, const char *name, unsigned int flags, DBusError *error) { DBusMessage *message, *reply; dbus_uint32_t result; _dbus_return_val_if_fail (connection != NULL, 0); _dbus_return_val_if_fail (name != NULL, 0); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0); _dbus_return_val_if_error_is_set (error, 0); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "RequestName"); if (message == NULL) { _DBUS_SET_OOM (error); return -1; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return -1; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return -1; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, &result, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } dbus_message_unref (reply); return result; } /** * Asks the bus to unassign the given name from this connection by * invoking the ReleaseName method on the bus. The "ReleaseName" * method is canonically documented in the D-Bus specification. * * Possible results are: #DBUS_RELEASE_NAME_REPLY_RELEASED * which means you owned the name or were in the queue to own it, * and and now you don't own it and aren't in the queue. * #DBUS_RELEASE_NAME_REPLY_NOT_OWNER which means someone else * owns the name so you can't release it. * #DBUS_RELEASE_NAME_REPLY_NON_EXISTENT * which means nobody owned the name. * * @param connection the connection * @param name the name to remove * @param error location to store the error * @returns a result code, -1 if error is set */ int dbus_bus_release_name (DBusConnection *connection, const char *name, DBusError *error) { DBusMessage *message, *reply; dbus_uint32_t result; _dbus_return_val_if_fail (connection != NULL, 0); _dbus_return_val_if_fail (name != NULL, 0); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0); _dbus_return_val_if_error_is_set (error, 0); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ReleaseName"); if (message == NULL) { _DBUS_SET_OOM (error); return -1; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return -1; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return -1; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, &result, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } dbus_message_unref (reply); return result; } /** * Asks the bus whether a certain name has an owner. * * Using this can easily result in a race condition, * since an owner can appear or disappear after you * call this. * * If you want to request a name, just request it; * if you want to avoid replacing a current owner, * don't specify #DBUS_NAME_FLAG_REPLACE_EXISTING and * you will get an error if there's already an owner. * * @param connection the connection * @param name the name * @param error location to store any errors * @returns #TRUE if the name exists, #FALSE if not or on error */ dbus_bool_t dbus_bus_name_has_owner (DBusConnection *connection, const char *name, DBusError *error) { DBusMessage *message, *reply; dbus_bool_t exists; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE); _dbus_return_val_if_error_is_set (error, FALSE); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner"); if (message == NULL) { _DBUS_SET_OOM (error); return FALSE; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return FALSE; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_BOOLEAN, &exists, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return FALSE; } dbus_message_unref (reply); return exists; } /** * Starts a service that will request ownership of the given name. * The returned result will be one of be one of * #DBUS_START_REPLY_SUCCESS or #DBUS_START_REPLY_ALREADY_RUNNING if * successful. Pass #NULL if you don't care about the result. * * The flags parameter is for future expansion, currently you should * specify 0. * * It's often easier to avoid explicitly starting services, and * just send a method call to the service's bus name instead. * Method calls start a service to handle them by default * unless you call dbus_message_set_auto_start() to disable this * behavior. * * @param connection the connection * @param name the name we want the new service to request * @param flags the flags (should always be 0 for now) * @param result a place to store the result or #NULL * @param error location to store any errors * @returns #TRUE if the activation succeeded, #FALSE if not */ dbus_bool_t dbus_bus_start_service_by_name (DBusConnection *connection, const char *name, dbus_uint32_t flags, dbus_uint32_t *result, DBusError *error) { DBusMessage *msg; DBusMessage *reply; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE); msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "StartServiceByName"); if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) { dbus_message_unref (msg); _DBUS_SET_OOM (error); return FALSE; } reply = dbus_connection_send_with_reply_and_block (connection, msg, -1, error); dbus_message_unref (msg); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return FALSE; } if (result != NULL && !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, result, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return FALSE; } dbus_message_unref (reply); return TRUE; } static void send_no_return_values (DBusConnection *connection, DBusMessage *msg, DBusError *error) { if (error) { /* Block to check success codepath */ DBusMessage *reply; reply = dbus_connection_send_with_reply_and_block (connection, msg, -1, error); if (reply == NULL) _DBUS_ASSERT_ERROR_IS_SET (error); else dbus_message_unref (reply); } else { /* Silently-fail nonblocking codepath */ dbus_message_set_no_reply (msg, TRUE); dbus_connection_send (connection, msg, NULL); } } /** * Adds a match rule to match messages going through the message bus. * The "rule" argument is the string form of a match rule. * * If you pass #NULL for the error, this function will not * block; the match thus won't be added until you flush the * connection, and if there's an error adding the match * you won't find out about it. This is generally acceptable, since the * possible errors (including a lack of resources in the bus, the connection * having exceeded its quota of active match rules, or the match rule being * unparseable) are generally unrecoverable. * * If you pass non-#NULL for the error this function will * block until it gets a reply. This may be useful when using match rule keys * introduced in recent versions of D-Bus, like 'arg0namespace', to allow the * application to fall back to less efficient match rules supported by older * versions of the daemon if the running version is not new enough; or when * using user-supplied rules rather than rules hard-coded at compile time. * * Normal API conventions would have the function return * a boolean value indicating whether the error was set, * but that would require blocking always to determine * the return value. * * The AddMatch method is fully documented in the D-Bus * specification. For quick reference, the format of the * match rules is discussed here, but the specification * is the canonical version of this information. * * Rules are specified as a string of comma separated * key/value pairs. An example is * "type='signal',sender='org.freedesktop.DBus', * interface='org.freedesktop.DBus',member='Foo', * path='/bar/foo',destination=':452345.34'" * * Possible keys you can match on are type, sender, * interface, member, path, destination and numbered * keys to match message args (keys are 'arg0', 'arg1', etc.). * Omitting a key from the rule indicates * a wildcard match. For instance omitting * the member from a match rule but adding a sender would * let all messages from that sender through regardless of * the member. * * Matches are inclusive not exclusive so as long as one * rule matches the message will get through. It is important * to note this because every time a message is received the * application will be paged into memory to process it. This * can cause performance problems such as draining batteries * on embedded platforms. * * If you match message args ('arg0', 'arg1', and so forth) * only string arguments will match. That is, arg0='5' means * match the string "5" not the integer 5. * * Currently there is no way to match against non-string arguments. * * A specialised form of wildcard matching on arguments is * supported for path-like namespaces. If your argument match has * a 'path' suffix (eg: "arg0path='/some/path/'") then it is * considered a match if the argument exactly matches the given * string or if one of them ends in a '/' and is a prefix of the * other. * * Matching on interface is tricky because method call * messages only optionally specify the interface. * If a message omits the interface, then it will NOT match * if the rule specifies an interface name. This means match * rules on method calls should not usually give an interface. * * However, signal messages are required to include the interface * so when matching signals usually you should specify the interface * in the match rule. * * For security reasons, you can match arguments only up to * #DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER. * * Match rules have a maximum length of #DBUS_MAXIMUM_MATCH_RULE_LENGTH * bytes. * * Both of these maximums are much higher than you're likely to need, * they only exist because the D-Bus bus daemon has fixed limits on * all resource usage. * * @param connection connection to the message bus * @param rule textual form of match rule * @param error location to store any errors */ void dbus_bus_add_match (DBusConnection *connection, const char *rule, DBusError *error) { DBusMessage *msg; _dbus_return_if_fail (rule != NULL); msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "AddMatch"); if (msg == NULL) { _DBUS_SET_OOM (error); return; } if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule, DBUS_TYPE_INVALID)) { dbus_message_unref (msg); _DBUS_SET_OOM (error); return; } send_no_return_values (connection, msg, error); dbus_message_unref (msg); } /** * Removes a previously-added match rule "by value" (the most * recently-added identical rule gets removed). The "rule" argument * is the string form of a match rule. * * The bus compares match rules semantically, not textually, so * whitespace and ordering don't have to be identical to * the rule you passed to dbus_bus_add_match(). * * If you pass #NULL for the error, this function will not * block; otherwise it will. See detailed explanation in * docs for dbus_bus_add_match(). * * @param connection connection to the message bus * @param rule textual form of match rule * @param error location to store any errors */ void dbus_bus_remove_match (DBusConnection *connection, const char *rule, DBusError *error) { DBusMessage *msg; _dbus_return_if_fail (rule != NULL); msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "RemoveMatch"); if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule, DBUS_TYPE_INVALID)) { dbus_message_unref (msg); _DBUS_SET_OOM (error); return; } send_no_return_values (connection, msg, error); dbus_message_unref (msg); } /** @} */ dbus-1.10.6/dbus/dbus-auth.h0000644000175000017500000001035612602773110015544 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-auth.h Authentication * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_AUTH_H #define DBUS_AUTH_H #include #include #include #include DBUS_BEGIN_DECLS typedef struct DBusAuth DBusAuth; typedef enum { DBUS_AUTH_STATE_WAITING_FOR_INPUT, DBUS_AUTH_STATE_WAITING_FOR_MEMORY, DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND, DBUS_AUTH_STATE_NEED_DISCONNECT, DBUS_AUTH_STATE_AUTHENTICATED } DBusAuthState; DBUS_PRIVATE_EXPORT DBusAuth* _dbus_auth_server_new (const DBusString *guid); DBUS_PRIVATE_EXPORT DBusAuth* _dbus_auth_client_new (void); DBUS_PRIVATE_EXPORT DBusAuth* _dbus_auth_ref (DBusAuth *auth); DBUS_PRIVATE_EXPORT void _dbus_auth_unref (DBusAuth *auth); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_auth_set_mechanisms (DBusAuth *auth, const char **mechanisms); DBUS_PRIVATE_EXPORT DBusAuthState _dbus_auth_do_work (DBusAuth *auth); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth, const DBusString **str); DBUS_PRIVATE_EXPORT void _dbus_auth_bytes_sent (DBusAuth *auth, int bytes_sent); DBUS_PRIVATE_EXPORT void _dbus_auth_get_buffer (DBusAuth *auth, DBusString **buffer); DBUS_PRIVATE_EXPORT void _dbus_auth_return_buffer (DBusAuth *auth, DBusString *buffer); DBUS_PRIVATE_EXPORT void _dbus_auth_get_unused_bytes (DBusAuth *auth, const DBusString **str); DBUS_PRIVATE_EXPORT void _dbus_auth_delete_unused_bytes (DBusAuth *auth); dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth); dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth, const DBusString *plaintext, DBusString *encoded); dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth); dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth, const DBusString *encoded, DBusString *plaintext); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_auth_set_credentials (DBusAuth *auth, DBusCredentials *credentials); DBUS_PRIVATE_EXPORT DBusCredentials* _dbus_auth_get_identity (DBusAuth *auth); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_auth_set_context (DBusAuth *auth, const DBusString *context); const char* _dbus_auth_get_guid_from_server(DBusAuth *auth); void _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b); dbus_bool_t _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth); DBUS_END_DECLS #endif /* DBUS_AUTH_H */ dbus-1.10.6/dbus/dbus-auth.c0000644000175000017500000023250612602773110015542 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-auth.c Authentication * * Copyright (C) 2002, 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-auth.h" #include "dbus-string.h" #include "dbus-list.h" #include "dbus-internals.h" #include "dbus-keyring.h" #include "dbus-sha.h" #include "dbus-protocol.h" #include "dbus-credentials.h" /** * @defgroup DBusAuth Authentication * @ingroup DBusInternals * @brief DBusAuth object * * DBusAuth manages the authentication negotiation when a connection * is first established, and also manages any encryption used over a * connection. * * @todo some SASL profiles require sending the empty string as a * challenge/response, but we don't currently allow that in our * protocol. * * @todo right now sometimes both ends will block waiting for input * from the other end, e.g. if there's an error during * DBUS_COOKIE_SHA1. * * @todo the cookie keyring needs to be cached globally not just * per-auth (which raises threadsafety issues too) * * @todo grep FIXME in dbus-auth.c */ /** * @defgroup DBusAuthInternals Authentication implementation details * @ingroup DBusInternals * @brief DBusAuth implementation details * * Private details of authentication code. * * @{ */ /** * This function appends an initial client response to the given string */ typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth, DBusString *response); /** * This function processes a block of data received from the peer. * i.e. handles a DATA command. */ typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth, const DBusString *data); /** * This function encodes a block of data from the peer. */ typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth, const DBusString *data, DBusString *encoded); /** * This function decodes a block of data from the peer. */ typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, const DBusString *data, DBusString *decoded); /** * This function is called when the mechanism is abandoned. */ typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); /** * Virtual table representing a particular auth mechanism. */ typedef struct { const char *mechanism; /**< Name of the mechanism */ DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */ DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */ DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */ DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */ DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */ DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */ DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */ DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */ DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */ } DBusAuthMechanismHandler; /** * Enumeration for the known authentication commands. */ typedef enum { DBUS_AUTH_COMMAND_AUTH, DBUS_AUTH_COMMAND_CANCEL, DBUS_AUTH_COMMAND_DATA, DBUS_AUTH_COMMAND_BEGIN, DBUS_AUTH_COMMAND_REJECTED, DBUS_AUTH_COMMAND_OK, DBUS_AUTH_COMMAND_ERROR, DBUS_AUTH_COMMAND_UNKNOWN, DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD, DBUS_AUTH_COMMAND_AGREE_UNIX_FD } DBusAuthCommand; /** * Auth state function, determines the reaction to incoming events for * a particular state. Returns whether we had enough memory to * complete the operation. */ typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); /** * Information about a auth state. */ typedef struct { const char *name; /**< Name of the state */ DBusAuthStateFunction handler; /**< State function for this state */ } DBusAuthStateData; /** * Internal members of DBusAuth. */ struct DBusAuth { int refcount; /**< reference count */ const char *side; /**< Client or server */ DBusString incoming; /**< Incoming data buffer */ DBusString outgoing; /**< Outgoing data buffer */ const DBusAuthStateData *state; /**< Current protocol state */ const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */ DBusString identity; /**< Current identity we're authorizing * as. */ DBusCredentials *credentials; /**< Credentials read from socket */ DBusCredentials *authorized_identity; /**< Credentials that are authorized */ DBusCredentials *desired_identity; /**< Identity client has requested */ DBusString context; /**< Cookie scope */ DBusKeyring *keyring; /**< Keyring for cookie mechanism. */ int cookie_id; /**< ID of cookie to use */ DBusString challenge; /**< Challenge sent to client */ char **allowed_mechs; /**< Mechanisms we're allowed to use, * or #NULL if we can use any */ unsigned int needed_memory : 1; /**< We needed memory to continue since last * successful getting something done */ unsigned int already_got_mechanisms : 1; /**< Client already got mech list */ unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */ unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */ unsigned int unix_fd_possible : 1; /**< This side could do unix fd passing */ unsigned int unix_fd_negotiated : 1; /**< Unix fd was successfully negotiated */ }; /** * "Subclass" of DBusAuth for client side */ typedef struct { DBusAuth base; /**< Parent class */ DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */ DBusString guid_from_server; /**< GUID received from server */ } DBusAuthClient; /** * "Subclass" of DBusAuth for server side. */ typedef struct { DBusAuth base; /**< Parent class */ int failures; /**< Number of times client has been rejected */ int max_failures; /**< Number of times we reject before disconnect */ DBusString guid; /**< Our globally unique ID in hex encoding */ } DBusAuthServer; static void goto_state (DBusAuth *auth, const DBusAuthStateData *new_state); static dbus_bool_t send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech); static dbus_bool_t send_data (DBusAuth *auth, DBusString *data); static dbus_bool_t send_rejected (DBusAuth *auth); static dbus_bool_t send_error (DBusAuth *auth, const char *message); static dbus_bool_t send_ok (DBusAuth *auth); static dbus_bool_t send_begin (DBusAuth *auth); static dbus_bool_t send_cancel (DBusAuth *auth); static dbus_bool_t send_negotiate_unix_fd (DBusAuth *auth); static dbus_bool_t send_agree_unix_fd (DBusAuth *auth); /** * Client states */ static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static const DBusAuthStateData server_state_waiting_for_auth = { "WaitingForAuth", handle_server_state_waiting_for_auth }; static const DBusAuthStateData server_state_waiting_for_data = { "WaitingForData", handle_server_state_waiting_for_data }; static const DBusAuthStateData server_state_waiting_for_begin = { "WaitingForBegin", handle_server_state_waiting_for_begin }; /** * Client states */ static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd (DBusAuth *auth, DBusAuthCommand command, const DBusString *args); static const DBusAuthStateData client_state_need_send_auth = { "NeedSendAuth", NULL }; static const DBusAuthStateData client_state_waiting_for_data = { "WaitingForData", handle_client_state_waiting_for_data }; static const DBusAuthStateData client_state_waiting_for_ok = { "WaitingForOK", handle_client_state_waiting_for_ok }; static const DBusAuthStateData client_state_waiting_for_reject = { "WaitingForReject", handle_client_state_waiting_for_reject }; static const DBusAuthStateData client_state_waiting_for_agree_unix_fd = { "WaitingForAgreeUnixFD", handle_client_state_waiting_for_agree_unix_fd }; /** * Common terminal states. Terminal states have handler == NULL. */ static const DBusAuthStateData common_state_authenticated = { "Authenticated", NULL }; static const DBusAuthStateData common_state_need_disconnect = { "NeedDisconnect", NULL }; static const char auth_side_client[] = "client"; static const char auth_side_server[] = "server"; /** * @param auth the auth conversation * @returns #TRUE if the conversation is the server side */ #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server) /** * @param auth the auth conversation * @returns #TRUE if the conversation is the client side */ #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client) /** * @param auth the auth conversation * @returns auth cast to DBusAuthClient */ #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth)) /** * @param auth the auth conversation * @returns auth cast to DBusAuthServer */ #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth)) /** * The name of the auth ("client" or "server") * @param auth the auth conversation * @returns a string */ #define DBUS_AUTH_NAME(auth) ((auth)->side) static DBusAuth* _dbus_auth_new (int size) { DBusAuth *auth; auth = dbus_malloc0 (size); if (auth == NULL) return NULL; auth->refcount = 1; auth->keyring = NULL; auth->cookie_id = -1; /* note that we don't use the max string length feature, * because you can't use that feature if you're going to * try to recover from out-of-memory (it creates * what looks like unrecoverable inability to alloc * more space in the string). But we do handle * overlong buffers in _dbus_auth_do_work(). */ if (!_dbus_string_init (&auth->incoming)) goto enomem_0; if (!_dbus_string_init (&auth->outgoing)) goto enomem_1; if (!_dbus_string_init (&auth->identity)) goto enomem_2; if (!_dbus_string_init (&auth->context)) goto enomem_3; if (!_dbus_string_init (&auth->challenge)) goto enomem_4; /* default context if none is specified */ if (!_dbus_string_append (&auth->context, "org_freedesktop_general")) goto enomem_5; auth->credentials = _dbus_credentials_new (); if (auth->credentials == NULL) goto enomem_6; auth->authorized_identity = _dbus_credentials_new (); if (auth->authorized_identity == NULL) goto enomem_7; auth->desired_identity = _dbus_credentials_new (); if (auth->desired_identity == NULL) goto enomem_8; return auth; #if 0 enomem_9: _dbus_credentials_unref (auth->desired_identity); #endif enomem_8: _dbus_credentials_unref (auth->authorized_identity); enomem_7: _dbus_credentials_unref (auth->credentials); enomem_6: /* last alloc was an append to context, which is freed already below */ ; enomem_5: _dbus_string_free (&auth->challenge); enomem_4: _dbus_string_free (&auth->context); enomem_3: _dbus_string_free (&auth->identity); enomem_2: _dbus_string_free (&auth->outgoing); enomem_1: _dbus_string_free (&auth->incoming); enomem_0: dbus_free (auth); return NULL; } static void shutdown_mech (DBusAuth *auth) { /* Cancel any auth */ auth->already_asked_for_initial_response = FALSE; _dbus_string_set_length (&auth->identity, 0); _dbus_credentials_clear (auth->authorized_identity); _dbus_credentials_clear (auth->desired_identity); if (auth->mech != NULL) { _dbus_verbose ("%s: Shutting down mechanism %s\n", DBUS_AUTH_NAME (auth), auth->mech->mechanism); if (DBUS_AUTH_IS_CLIENT (auth)) (* auth->mech->client_shutdown_func) (auth); else (* auth->mech->server_shutdown_func) (auth); auth->mech = NULL; } } /* * DBUS_COOKIE_SHA1 mechanism */ /* Returns TRUE but with an empty string hash if the * cookie_id isn't known. As with all this code * TRUE just means we had enough memory. */ static dbus_bool_t sha1_compute_hash (DBusAuth *auth, int cookie_id, const DBusString *server_challenge, const DBusString *client_challenge, DBusString *hash) { DBusString cookie; DBusString to_hash; dbus_bool_t retval; _dbus_assert (auth->keyring != NULL); retval = FALSE; if (!_dbus_string_init (&cookie)) return FALSE; if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id, &cookie)) goto out_0; if (_dbus_string_get_length (&cookie) == 0) { retval = TRUE; goto out_0; } if (!_dbus_string_init (&to_hash)) goto out_0; if (!_dbus_string_copy (server_challenge, 0, &to_hash, _dbus_string_get_length (&to_hash))) goto out_1; if (!_dbus_string_append (&to_hash, ":")) goto out_1; if (!_dbus_string_copy (client_challenge, 0, &to_hash, _dbus_string_get_length (&to_hash))) goto out_1; if (!_dbus_string_append (&to_hash, ":")) goto out_1; if (!_dbus_string_copy (&cookie, 0, &to_hash, _dbus_string_get_length (&to_hash))) goto out_1; if (!_dbus_sha_compute (&to_hash, hash)) goto out_1; retval = TRUE; out_1: _dbus_string_zero (&to_hash); _dbus_string_free (&to_hash); out_0: _dbus_string_zero (&cookie); _dbus_string_free (&cookie); return retval; } /** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of * entropy, we use 128. This is the number of bytes in the random * challenge. */ #define N_CHALLENGE_BYTES (128/8) static dbus_bool_t sha1_handle_first_client_response (DBusAuth *auth, const DBusString *data) { /* We haven't sent a challenge yet, we're expecting a desired * username from the client. */ DBusString tmp; DBusString tmp2; dbus_bool_t retval = FALSE; DBusError error = DBUS_ERROR_INIT; _dbus_string_set_length (&auth->challenge, 0); if (_dbus_string_get_length (data) > 0) { if (_dbus_string_get_length (&auth->identity) > 0) { /* Tried to send two auth identities, wtf */ _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } else { /* this is our auth identity */ if (!_dbus_string_copy (data, 0, &auth->identity, 0)) return FALSE; } } if (!_dbus_credentials_add_from_user (auth->desired_identity, data)) { _dbus_verbose ("%s: Did not get a valid username from client\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } if (!_dbus_string_init (&tmp)) return FALSE; if (!_dbus_string_init (&tmp2)) { _dbus_string_free (&tmp); return FALSE; } /* we cache the keyring for speed, so here we drop it if it's the * wrong one. FIXME caching the keyring here is useless since we use * a different DBusAuth for every connection. */ if (auth->keyring && !_dbus_keyring_is_for_credentials (auth->keyring, auth->desired_identity)) { _dbus_keyring_unref (auth->keyring); auth->keyring = NULL; } if (auth->keyring == NULL) { auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity, &auth->context, &error); if (auth->keyring == NULL) { if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); goto out; } else { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("%s: Error loading keyring: %s\n", DBUS_AUTH_NAME (auth), error.message); if (send_rejected (auth)) retval = TRUE; /* retval is only about mem */ dbus_error_free (&error); goto out; } } else { _dbus_assert (!dbus_error_is_set (&error)); } } _dbus_assert (auth->keyring != NULL); auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); if (auth->cookie_id < 0) { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n", DBUS_AUTH_NAME (auth), error.message); if (send_rejected (auth)) retval = TRUE; dbus_error_free (&error); goto out; } else { _dbus_assert (!dbus_error_is_set (&error)); } if (!_dbus_string_copy (&auth->context, 0, &tmp2, _dbus_string_get_length (&tmp2))) goto out; if (!_dbus_string_append (&tmp2, " ")) goto out; if (!_dbus_string_append_int (&tmp2, auth->cookie_id)) goto out; if (!_dbus_string_append (&tmp2, " ")) goto out; if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error)) { if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); goto out; } else { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("%s: Error generating challenge: %s\n", DBUS_AUTH_NAME (auth), error.message); if (send_rejected (auth)) retval = TRUE; /* retval is only about mem */ dbus_error_free (&error); goto out; } } _dbus_string_set_length (&auth->challenge, 0); if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0)) goto out; if (!_dbus_string_hex_encode (&tmp, 0, &tmp2, _dbus_string_get_length (&tmp2))) goto out; if (!send_data (auth, &tmp2)) goto out; goto_state (auth, &server_state_waiting_for_data); retval = TRUE; out: _dbus_string_zero (&tmp); _dbus_string_free (&tmp); _dbus_string_zero (&tmp2); _dbus_string_free (&tmp2); return retval; } static dbus_bool_t sha1_handle_second_client_response (DBusAuth *auth, const DBusString *data) { /* We are expecting a response which is the hex-encoded client * challenge, space, then SHA-1 hash of the concatenation of our * challenge, ":", client challenge, ":", secret key, all * hex-encoded. */ int i; DBusString client_challenge; DBusString client_hash; dbus_bool_t retval; DBusString correct_hash; retval = FALSE; if (!_dbus_string_find_blank (data, 0, &i)) { _dbus_verbose ("%s: no space separator in client response\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } if (!_dbus_string_init (&client_challenge)) goto out_0; if (!_dbus_string_init (&client_hash)) goto out_1; if (!_dbus_string_copy_len (data, 0, i, &client_challenge, 0)) goto out_2; _dbus_string_skip_blank (data, i, &i); if (!_dbus_string_copy_len (data, i, _dbus_string_get_length (data) - i, &client_hash, 0)) goto out_2; if (_dbus_string_get_length (&client_challenge) == 0 || _dbus_string_get_length (&client_hash) == 0) { _dbus_verbose ("%s: zero-length client challenge or hash\n", DBUS_AUTH_NAME (auth)); if (send_rejected (auth)) retval = TRUE; goto out_2; } if (!_dbus_string_init (&correct_hash)) goto out_2; if (!sha1_compute_hash (auth, auth->cookie_id, &auth->challenge, &client_challenge, &correct_hash)) goto out_3; /* if cookie_id was invalid, then we get an empty hash */ if (_dbus_string_get_length (&correct_hash) == 0) { if (send_rejected (auth)) retval = TRUE; goto out_3; } if (!_dbus_string_equal (&client_hash, &correct_hash)) { if (send_rejected (auth)) retval = TRUE; goto out_3; } if (!_dbus_credentials_add_credentials (auth->authorized_identity, auth->desired_identity)) goto out_3; /* Copy process ID from the socket credentials if it's there */ if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_UNIX_PROCESS_ID, auth->credentials)) goto out_3; if (!send_ok (auth)) goto out_3; _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n", DBUS_AUTH_NAME (auth)); retval = TRUE; out_3: _dbus_string_zero (&correct_hash); _dbus_string_free (&correct_hash); out_2: _dbus_string_zero (&client_hash); _dbus_string_free (&client_hash); out_1: _dbus_string_free (&client_challenge); out_0: return retval; } static dbus_bool_t handle_server_data_cookie_sha1_mech (DBusAuth *auth, const DBusString *data) { if (auth->cookie_id < 0) return sha1_handle_first_client_response (auth, data); else return sha1_handle_second_client_response (auth, data); } static void handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth) { auth->cookie_id = -1; _dbus_string_set_length (&auth->challenge, 0); } static dbus_bool_t handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth, DBusString *response) { DBusString username; dbus_bool_t retval; retval = FALSE; if (!_dbus_string_init (&username)) return FALSE; if (!_dbus_append_user_from_current_process (&username)) goto out_0; if (!_dbus_string_hex_encode (&username, 0, response, _dbus_string_get_length (response))) goto out_0; retval = TRUE; out_0: _dbus_string_free (&username); return retval; } static dbus_bool_t handle_client_data_cookie_sha1_mech (DBusAuth *auth, const DBusString *data) { /* The data we get from the server should be the cookie context * name, the cookie ID, and the server challenge, separated by * spaces. We send back our challenge string and the correct hash. */ dbus_bool_t retval = FALSE; DBusString context; DBusString cookie_id_str; DBusString server_challenge; DBusString client_challenge; DBusString correct_hash; DBusString tmp; int i, j; long val; DBusError error = DBUS_ERROR_INIT; if (!_dbus_string_find_blank (data, 0, &i)) { if (send_error (auth, "Server did not send context/ID/challenge properly")) retval = TRUE; goto out_0; } if (!_dbus_string_init (&context)) goto out_0; if (!_dbus_string_copy_len (data, 0, i, &context, 0)) goto out_1; _dbus_string_skip_blank (data, i, &i); if (!_dbus_string_find_blank (data, i, &j)) { if (send_error (auth, "Server did not send context/ID/challenge properly")) retval = TRUE; goto out_1; } if (!_dbus_string_init (&cookie_id_str)) goto out_1; if (!_dbus_string_copy_len (data, i, j - i, &cookie_id_str, 0)) goto out_2; if (!_dbus_string_init (&server_challenge)) goto out_2; i = j; _dbus_string_skip_blank (data, i, &i); j = _dbus_string_get_length (data); if (!_dbus_string_copy_len (data, i, j - i, &server_challenge, 0)) goto out_3; if (!_dbus_keyring_validate_context (&context)) { if (send_error (auth, "Server sent invalid cookie context")) retval = TRUE; goto out_3; } if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL)) { if (send_error (auth, "Could not parse cookie ID as an integer")) retval = TRUE; goto out_3; } if (_dbus_string_get_length (&server_challenge) == 0) { if (send_error (auth, "Empty server challenge string")) retval = TRUE; goto out_3; } if (auth->keyring == NULL) { auth->keyring = _dbus_keyring_new_for_credentials (NULL, &context, &error); if (auth->keyring == NULL) { if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); goto out_3; } else { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("%s: Error loading keyring: %s\n", DBUS_AUTH_NAME (auth), error.message); if (send_error (auth, "Could not load cookie file")) retval = TRUE; /* retval is only about mem */ dbus_error_free (&error); goto out_3; } } else { _dbus_assert (!dbus_error_is_set (&error)); } } _dbus_assert (auth->keyring != NULL); if (!_dbus_string_init (&tmp)) goto out_3; if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error)) { if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { dbus_error_free (&error); goto out_4; } else { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("%s: Failed to generate challenge: %s\n", DBUS_AUTH_NAME (auth), error.message); if (send_error (auth, "Failed to generate challenge")) retval = TRUE; /* retval is only about mem */ dbus_error_free (&error); goto out_4; } } if (!_dbus_string_init (&client_challenge)) goto out_4; if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0)) goto out_5; if (!_dbus_string_init (&correct_hash)) goto out_5; if (!sha1_compute_hash (auth, val, &server_challenge, &client_challenge, &correct_hash)) goto out_6; if (_dbus_string_get_length (&correct_hash) == 0) { /* couldn't find the cookie ID or something */ if (send_error (auth, "Don't have the requested cookie ID")) retval = TRUE; goto out_6; } _dbus_string_set_length (&tmp, 0); if (!_dbus_string_copy (&client_challenge, 0, &tmp, _dbus_string_get_length (&tmp))) goto out_6; if (!_dbus_string_append (&tmp, " ")) goto out_6; if (!_dbus_string_copy (&correct_hash, 0, &tmp, _dbus_string_get_length (&tmp))) goto out_6; if (!send_data (auth, &tmp)) goto out_6; retval = TRUE; out_6: _dbus_string_zero (&correct_hash); _dbus_string_free (&correct_hash); out_5: _dbus_string_free (&client_challenge); out_4: _dbus_string_zero (&tmp); _dbus_string_free (&tmp); out_3: _dbus_string_free (&server_challenge); out_2: _dbus_string_free (&cookie_id_str); out_1: _dbus_string_free (&context); out_0: return retval; } static void handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth) { auth->cookie_id = -1; _dbus_string_set_length (&auth->challenge, 0); } /* * EXTERNAL mechanism */ static dbus_bool_t handle_server_data_external_mech (DBusAuth *auth, const DBusString *data) { if (_dbus_credentials_are_anonymous (auth->credentials)) { _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } if (_dbus_string_get_length (data) > 0) { if (_dbus_string_get_length (&auth->identity) > 0) { /* Tried to send two auth identities, wtf */ _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } else { /* this is our auth identity */ if (!_dbus_string_copy (data, 0, &auth->identity, 0)) return FALSE; } } /* Poke client for an auth identity, if none given */ if (_dbus_string_get_length (&auth->identity) == 0 && !auth->already_asked_for_initial_response) { if (send_data (auth, NULL)) { _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n", DBUS_AUTH_NAME (auth)); auth->already_asked_for_initial_response = TRUE; goto_state (auth, &server_state_waiting_for_data); return TRUE; } else return FALSE; } _dbus_credentials_clear (auth->desired_identity); /* If auth->identity is still empty here, then client * responded with an empty string after we poked it for * an initial response. This means to try to auth the * identity provided in the credentials. */ if (_dbus_string_get_length (&auth->identity) == 0) { if (!_dbus_credentials_add_credentials (auth->desired_identity, auth->credentials)) { return FALSE; /* OOM */ } } else { if (!_dbus_credentials_add_from_user (auth->desired_identity, &auth->identity)) { _dbus_verbose ("%s: could not get credentials from uid string\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } } if (_dbus_credentials_are_anonymous (auth->desired_identity)) { _dbus_verbose ("%s: desired user %s is no good\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&auth->identity)); return send_rejected (auth); } if (_dbus_credentials_are_superset (auth->credentials, auth->desired_identity)) { /* client has authenticated */ if (!_dbus_credentials_add_credentials (auth->authorized_identity, auth->desired_identity)) return FALSE; /* also copy misc process info from the socket credentials */ if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_UNIX_PROCESS_ID, auth->credentials)) return FALSE; if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, auth->credentials)) return FALSE; if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_LINUX_SECURITY_LABEL, auth->credentials)) return FALSE; if (!send_ok (auth)) return FALSE; _dbus_verbose ("%s: authenticated client based on socket credentials\n", DBUS_AUTH_NAME (auth)); return TRUE; } else { _dbus_verbose ("%s: desired identity not found in socket credentials\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } } static void handle_server_shutdown_external_mech (DBusAuth *auth) { } static dbus_bool_t handle_client_initial_response_external_mech (DBusAuth *auth, DBusString *response) { /* We always append our UID as an initial response, so the server * doesn't have to send back an empty challenge to check whether we * want to specify an identity. i.e. this avoids a round trip that * the spec for the EXTERNAL mechanism otherwise requires. */ DBusString plaintext; if (!_dbus_string_init (&plaintext)) return FALSE; if (!_dbus_append_user_from_current_process (&plaintext)) goto failed; if (!_dbus_string_hex_encode (&plaintext, 0, response, _dbus_string_get_length (response))) goto failed; _dbus_string_free (&plaintext); return TRUE; failed: _dbus_string_free (&plaintext); return FALSE; } static dbus_bool_t handle_client_data_external_mech (DBusAuth *auth, const DBusString *data) { return TRUE; } static void handle_client_shutdown_external_mech (DBusAuth *auth) { } /* * ANONYMOUS mechanism */ static dbus_bool_t handle_server_data_anonymous_mech (DBusAuth *auth, const DBusString *data) { if (_dbus_string_get_length (data) > 0) { /* Client is allowed to send "trace" data, the only defined * meaning is that if it contains '@' it is an email address, * and otherwise it is anything else, and it's supposed to be * UTF-8 */ if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data))) { _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n", DBUS_AUTH_NAME (auth)); return send_rejected (auth); } _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (data)); } /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ _dbus_credentials_clear (auth->desired_identity); /* Copy process ID from the socket credentials */ if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_UNIX_PROCESS_ID, auth->credentials)) return FALSE; /* Anonymous is always allowed */ if (!send_ok (auth)) return FALSE; _dbus_verbose ("%s: authenticated client as anonymous\n", DBUS_AUTH_NAME (auth)); return TRUE; } static void handle_server_shutdown_anonymous_mech (DBusAuth *auth) { } static dbus_bool_t handle_client_initial_response_anonymous_mech (DBusAuth *auth, DBusString *response) { /* Our initial response is a "trace" string which must be valid UTF-8 * and must be an email address if it contains '@'. * We just send the dbus implementation info, like a user-agent or * something, because... why not. There's nothing guaranteed here * though, we could change it later. */ DBusString plaintext; if (!_dbus_string_init (&plaintext)) return FALSE; if (!_dbus_string_append (&plaintext, "libdbus " DBUS_VERSION_STRING)) goto failed; if (!_dbus_string_hex_encode (&plaintext, 0, response, _dbus_string_get_length (response))) goto failed; _dbus_string_free (&plaintext); return TRUE; failed: _dbus_string_free (&plaintext); return FALSE; } static dbus_bool_t handle_client_data_anonymous_mech (DBusAuth *auth, const DBusString *data) { return TRUE; } static void handle_client_shutdown_anonymous_mech (DBusAuth *auth) { } /* Put mechanisms here in order of preference. * Right now we have: * * - EXTERNAL checks socket credentials (or in the future, other info from the OS) * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE * - ANONYMOUS checks nothing but doesn't auth the person as a user * * We might ideally add a mechanism to chain to Cyrus SASL so we can * use its mechanisms as well. * */ static const DBusAuthMechanismHandler all_mechanisms[] = { { "EXTERNAL", handle_server_data_external_mech, NULL, NULL, handle_server_shutdown_external_mech, handle_client_initial_response_external_mech, handle_client_data_external_mech, NULL, NULL, handle_client_shutdown_external_mech }, { "DBUS_COOKIE_SHA1", handle_server_data_cookie_sha1_mech, NULL, NULL, handle_server_shutdown_cookie_sha1_mech, handle_client_initial_response_cookie_sha1_mech, handle_client_data_cookie_sha1_mech, NULL, NULL, handle_client_shutdown_cookie_sha1_mech }, { "ANONYMOUS", handle_server_data_anonymous_mech, NULL, NULL, handle_server_shutdown_anonymous_mech, handle_client_initial_response_anonymous_mech, handle_client_data_anonymous_mech, NULL, NULL, handle_client_shutdown_anonymous_mech }, { NULL, NULL } }; static const DBusAuthMechanismHandler* find_mech (const DBusString *name, char **allowed_mechs) { int i; if (allowed_mechs != NULL && !_dbus_string_array_contains ((const char**) allowed_mechs, _dbus_string_get_const_data (name))) return NULL; i = 0; while (all_mechanisms[i].mechanism != NULL) { if (_dbus_string_equal_c_str (name, all_mechanisms[i].mechanism)) return &all_mechanisms[i]; ++i; } return NULL; } static dbus_bool_t send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) { DBusString auth_command; if (!_dbus_string_init (&auth_command)) return FALSE; if (!_dbus_string_append (&auth_command, "AUTH ")) { _dbus_string_free (&auth_command); return FALSE; } if (!_dbus_string_append (&auth_command, mech->mechanism)) { _dbus_string_free (&auth_command); return FALSE; } if (mech->client_initial_response_func != NULL) { if (!_dbus_string_append (&auth_command, " ")) { _dbus_string_free (&auth_command); return FALSE; } if (!(* mech->client_initial_response_func) (auth, &auth_command)) { _dbus_string_free (&auth_command); return FALSE; } } if (!_dbus_string_append (&auth_command, "\r\n")) { _dbus_string_free (&auth_command); return FALSE; } if (!_dbus_string_copy (&auth_command, 0, &auth->outgoing, _dbus_string_get_length (&auth->outgoing))) { _dbus_string_free (&auth_command); return FALSE; } _dbus_string_free (&auth_command); shutdown_mech (auth); auth->mech = mech; goto_state (auth, &client_state_waiting_for_data); return TRUE; } static dbus_bool_t send_data (DBusAuth *auth, DBusString *data) { int old_len; if (data == NULL || _dbus_string_get_length (data) == 0) return _dbus_string_append (&auth->outgoing, "DATA\r\n"); else { old_len = _dbus_string_get_length (&auth->outgoing); if (!_dbus_string_append (&auth->outgoing, "DATA ")) goto out; if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, _dbus_string_get_length (&auth->outgoing))) goto out; if (!_dbus_string_append (&auth->outgoing, "\r\n")) goto out; return TRUE; out: _dbus_string_set_length (&auth->outgoing, old_len); return FALSE; } } static dbus_bool_t send_rejected (DBusAuth *auth) { DBusString command; DBusAuthServer *server_auth; int i; if (!_dbus_string_init (&command)) return FALSE; if (!_dbus_string_append (&command, "REJECTED")) goto nomem; i = 0; while (all_mechanisms[i].mechanism != NULL) { if (!_dbus_string_append (&command, " ")) goto nomem; if (!_dbus_string_append (&command, all_mechanisms[i].mechanism)) goto nomem; ++i; } if (!_dbus_string_append (&command, "\r\n")) goto nomem; if (!_dbus_string_copy (&command, 0, &auth->outgoing, _dbus_string_get_length (&auth->outgoing))) goto nomem; shutdown_mech (auth); _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); server_auth = DBUS_AUTH_SERVER (auth); server_auth->failures += 1; if (server_auth->failures >= server_auth->max_failures) goto_state (auth, &common_state_need_disconnect); else goto_state (auth, &server_state_waiting_for_auth); _dbus_string_free (&command); return TRUE; nomem: _dbus_string_free (&command); return FALSE; } static dbus_bool_t send_error (DBusAuth *auth, const char *message) { return _dbus_string_append_printf (&auth->outgoing, "ERROR \"%s\"\r\n", message); } static dbus_bool_t send_ok (DBusAuth *auth) { int orig_len; orig_len = _dbus_string_get_length (&auth->outgoing); if (_dbus_string_append (&auth->outgoing, "OK ") && _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, 0, &auth->outgoing, _dbus_string_get_length (&auth->outgoing)) && _dbus_string_append (&auth->outgoing, "\r\n")) { goto_state (auth, &server_state_waiting_for_begin); return TRUE; } else { _dbus_string_set_length (&auth->outgoing, orig_len); return FALSE; } } static dbus_bool_t send_begin (DBusAuth *auth) { if (!_dbus_string_append (&auth->outgoing, "BEGIN\r\n")) return FALSE; goto_state (auth, &common_state_authenticated); return TRUE; } static dbus_bool_t process_ok(DBusAuth *auth, const DBusString *args_from_ok) { int end_of_hex; /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); /* We decode the hex string to binary, using guid_from_server as scratch... */ end_of_hex = 0; if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) return FALSE; /* now clear out the scratch */ _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); if (end_of_hex != _dbus_string_get_length (args_from_ok) || end_of_hex == 0) { _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", end_of_hex, _dbus_string_get_length (args_from_ok)); goto_state (auth, &common_state_need_disconnect); return TRUE; } if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) { _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); return FALSE; } _dbus_verbose ("Got GUID '%s' from the server\n", _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); if (auth->unix_fd_possible) return send_negotiate_unix_fd(auth); _dbus_verbose("Not negotiating unix fd passing, since not possible\n"); return send_begin (auth); } static dbus_bool_t send_cancel (DBusAuth *auth) { if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) { goto_state (auth, &client_state_waiting_for_reject); return TRUE; } else return FALSE; } static dbus_bool_t process_data (DBusAuth *auth, const DBusString *args, DBusAuthDataFunction data_func) { int end; DBusString decoded; if (!_dbus_string_init (&decoded)) return FALSE; if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) { _dbus_string_free (&decoded); return FALSE; } if (_dbus_string_get_length (args) != end) { _dbus_string_free (&decoded); if (!send_error (auth, "Invalid hex encoding")) return FALSE; return TRUE; } #ifdef DBUS_ENABLE_VERBOSE_MODE if (_dbus_string_validate_ascii (&decoded, 0, _dbus_string_get_length (&decoded))) _dbus_verbose ("%s: data: '%s'\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&decoded)); #endif if (!(* data_func) (auth, &decoded)) { _dbus_string_free (&decoded); return FALSE; } _dbus_string_free (&decoded); return TRUE; } static dbus_bool_t send_negotiate_unix_fd (DBusAuth *auth) { if (!_dbus_string_append (&auth->outgoing, "NEGOTIATE_UNIX_FD\r\n")) return FALSE; goto_state (auth, &client_state_waiting_for_agree_unix_fd); return TRUE; } static dbus_bool_t send_agree_unix_fd (DBusAuth *auth) { _dbus_assert(auth->unix_fd_possible); auth->unix_fd_negotiated = TRUE; _dbus_verbose("Agreed to UNIX FD passing\n"); if (!_dbus_string_append (&auth->outgoing, "AGREE_UNIX_FD\r\n")) return FALSE; goto_state (auth, &server_state_waiting_for_begin); return TRUE; } static dbus_bool_t handle_auth (DBusAuth *auth, const DBusString *args) { if (_dbus_string_get_length (args) == 0) { /* No args to the auth, send mechanisms */ if (!send_rejected (auth)) return FALSE; return TRUE; } else { int i; DBusString mech; DBusString hex_response; _dbus_string_find_blank (args, 0, &i); if (!_dbus_string_init (&mech)) return FALSE; if (!_dbus_string_init (&hex_response)) { _dbus_string_free (&mech); return FALSE; } if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) goto failed; _dbus_string_skip_blank (args, i, &i); if (!_dbus_string_copy (args, i, &hex_response, 0)) goto failed; auth->mech = find_mech (&mech, auth->allowed_mechs); if (auth->mech != NULL) { _dbus_verbose ("%s: Trying mechanism %s\n", DBUS_AUTH_NAME (auth), auth->mech->mechanism); if (!process_data (auth, &hex_response, auth->mech->server_data_func)) goto failed; } else { /* Unsupported mechanism */ _dbus_verbose ("%s: Unsupported mechanism %s\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&mech)); if (!send_rejected (auth)) goto failed; } _dbus_string_free (&mech); _dbus_string_free (&hex_response); return TRUE; failed: auth->mech = NULL; _dbus_string_free (&mech); _dbus_string_free (&hex_response); return FALSE; } } static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_AUTH: return handle_auth (auth, args); case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_DATA: return send_error (auth, "Not currently in an auth conversation"); case DBUS_AUTH_COMMAND_BEGIN: goto_state (auth, &common_state_need_disconnect); return TRUE; case DBUS_AUTH_COMMAND_ERROR: return send_rejected (auth); case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: return send_error (auth, "Need to authenticate first"); case DBUS_AUTH_COMMAND_REJECTED: case DBUS_AUTH_COMMAND_OK: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: return send_error (auth, "Unknown command"); } } static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_AUTH: return send_error (auth, "Sent AUTH while another AUTH in progress"); case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_ERROR: return send_rejected (auth); case DBUS_AUTH_COMMAND_DATA: return process_data (auth, args, auth->mech->server_data_func); case DBUS_AUTH_COMMAND_BEGIN: goto_state (auth, &common_state_need_disconnect); return TRUE; case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: return send_error (auth, "Need to authenticate first"); case DBUS_AUTH_COMMAND_REJECTED: case DBUS_AUTH_COMMAND_OK: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: return send_error (auth, "Unknown command"); } } static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_AUTH: return send_error (auth, "Sent AUTH while expecting BEGIN"); case DBUS_AUTH_COMMAND_DATA: return send_error (auth, "Sent DATA while expecting BEGIN"); case DBUS_AUTH_COMMAND_BEGIN: goto_state (auth, &common_state_authenticated); return TRUE; case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: if (auth->unix_fd_possible) return send_agree_unix_fd(auth); else return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible"); case DBUS_AUTH_COMMAND_REJECTED: case DBUS_AUTH_COMMAND_OK: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: return send_error (auth, "Unknown command"); case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_ERROR: return send_rejected (auth); } } /* return FALSE if no memory, TRUE if all OK */ static dbus_bool_t get_word (const DBusString *str, int *start, DBusString *word) { int i; _dbus_string_skip_blank (str, *start, start); _dbus_string_find_blank (str, *start, &i); if (i > *start) { if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) return FALSE; *start = i; } return TRUE; } static dbus_bool_t record_mechanisms (DBusAuth *auth, const DBusString *args) { int next; int len; if (auth->already_got_mechanisms) return TRUE; len = _dbus_string_get_length (args); next = 0; while (next < len) { DBusString m; const DBusAuthMechanismHandler *mech; if (!_dbus_string_init (&m)) goto nomem; if (!get_word (args, &next, &m)) { _dbus_string_free (&m); goto nomem; } mech = find_mech (&m, auth->allowed_mechs); if (mech != NULL) { /* FIXME right now we try mechanisms in the order * the server lists them; should we do them in * some more deterministic order? * * Probably in all_mechanisms order, our order of * preference. Of course when the server is us, * it lists things in that order anyhow. */ if (mech != &all_mechanisms[0]) { _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", DBUS_AUTH_NAME (auth), mech->mechanism); if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, (void*) mech)) { _dbus_string_free (&m); goto nomem; } } else { _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", DBUS_AUTH_NAME (auth), mech->mechanism); } } else { _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&m)); } _dbus_string_free (&m); } auth->already_got_mechanisms = TRUE; return TRUE; nomem: _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); return FALSE; } static dbus_bool_t process_rejected (DBusAuth *auth, const DBusString *args) { const DBusAuthMechanismHandler *mech; DBusAuthClient *client; client = DBUS_AUTH_CLIENT (auth); if (!auth->already_got_mechanisms) { if (!record_mechanisms (auth, args)) return FALSE; } if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) { mech = client->mechs_to_try->data; if (!send_auth (auth, mech)) return FALSE; _dbus_list_pop_first (&client->mechs_to_try); _dbus_verbose ("%s: Trying mechanism %s\n", DBUS_AUTH_NAME (auth), mech->mechanism); } else { /* Give up */ _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", DBUS_AUTH_NAME (auth)); goto_state (auth, &common_state_need_disconnect); } return TRUE; } static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { _dbus_assert (auth->mech != NULL); switch (command) { case DBUS_AUTH_COMMAND_DATA: return process_data (auth, args, auth->mech->client_data_func); case DBUS_AUTH_COMMAND_REJECTED: return process_rejected (auth, args); case DBUS_AUTH_COMMAND_OK: return process_ok(auth, args); case DBUS_AUTH_COMMAND_ERROR: return send_cancel (auth); case DBUS_AUTH_COMMAND_AUTH: case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_BEGIN: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: return send_error (auth, "Unknown command"); } } static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_REJECTED: return process_rejected (auth, args); case DBUS_AUTH_COMMAND_OK: return process_ok(auth, args); case DBUS_AUTH_COMMAND_DATA: case DBUS_AUTH_COMMAND_ERROR: return send_cancel (auth); case DBUS_AUTH_COMMAND_AUTH: case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_BEGIN: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: return send_error (auth, "Unknown command"); } } static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_REJECTED: return process_rejected (auth, args); case DBUS_AUTH_COMMAND_AUTH: case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_DATA: case DBUS_AUTH_COMMAND_BEGIN: case DBUS_AUTH_COMMAND_OK: case DBUS_AUTH_COMMAND_ERROR: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: default: goto_state (auth, &common_state_need_disconnect); return TRUE; } } static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth, DBusAuthCommand command, const DBusString *args) { switch (command) { case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: _dbus_assert(auth->unix_fd_possible); auth->unix_fd_negotiated = TRUE; _dbus_verbose("Successfully negotiated UNIX FD passing\n"); return send_begin (auth); case DBUS_AUTH_COMMAND_ERROR: _dbus_assert(auth->unix_fd_possible); auth->unix_fd_negotiated = FALSE; _dbus_verbose("Failed to negotiate UNIX FD passing\n"); return send_begin (auth); case DBUS_AUTH_COMMAND_OK: case DBUS_AUTH_COMMAND_DATA: case DBUS_AUTH_COMMAND_REJECTED: case DBUS_AUTH_COMMAND_AUTH: case DBUS_AUTH_COMMAND_CANCEL: case DBUS_AUTH_COMMAND_BEGIN: case DBUS_AUTH_COMMAND_UNKNOWN: case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: default: return send_error (auth, "Unknown command"); } } /** * Mapping from command name to enum */ typedef struct { const char *name; /**< Name of the command */ DBusAuthCommand command; /**< Corresponding enum */ } DBusAuthCommandName; static const DBusAuthCommandName auth_command_names[] = { { "AUTH", DBUS_AUTH_COMMAND_AUTH }, { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, { "DATA", DBUS_AUTH_COMMAND_DATA }, { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, { "OK", DBUS_AUTH_COMMAND_OK }, { "ERROR", DBUS_AUTH_COMMAND_ERROR }, { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD }, { "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD } }; static DBusAuthCommand lookup_command_from_name (DBusString *command) { int i; for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) { if (_dbus_string_equal_c_str (command, auth_command_names[i].name)) return auth_command_names[i].command; } return DBUS_AUTH_COMMAND_UNKNOWN; } static void goto_state (DBusAuth *auth, const DBusAuthStateData *state) { _dbus_verbose ("%s: going from state %s to state %s\n", DBUS_AUTH_NAME (auth), auth->state->name, state->name); auth->state = state; } /* returns whether to call it again right away */ static dbus_bool_t process_command (DBusAuth *auth) { DBusAuthCommand command; DBusString line; DBusString args; int eol; int i, j; dbus_bool_t retval; /* _dbus_verbose ("%s: trying process_command()\n"); */ retval = FALSE; eol = 0; if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) return FALSE; if (!_dbus_string_init (&line)) { auth->needed_memory = TRUE; return FALSE; } if (!_dbus_string_init (&args)) { _dbus_string_free (&line); auth->needed_memory = TRUE; return FALSE; } if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) goto out; if (!_dbus_string_validate_ascii (&line, 0, _dbus_string_get_length (&line))) { _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", DBUS_AUTH_NAME (auth)); if (!send_error (auth, "Command contained non-ASCII")) goto out; else goto next_command; } _dbus_verbose ("%s: got command \"%s\"\n", DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&line)); _dbus_string_find_blank (&line, 0, &i); _dbus_string_skip_blank (&line, i, &j); if (j > i) _dbus_string_delete (&line, i, j - i); if (!_dbus_string_move (&line, i, &args, 0)) goto out; /* FIXME 1.0 we should probably validate that only the allowed * chars are in the command name */ command = lookup_command_from_name (&line); if (!(* auth->state->handler) (auth, command, &args)) goto out; next_command: /* We've succeeded in processing the whole command so drop it out * of the incoming buffer and return TRUE to try another command. */ _dbus_string_delete (&auth->incoming, 0, eol); /* kill the \r\n */ _dbus_string_delete (&auth->incoming, 0, 2); retval = TRUE; out: _dbus_string_free (&args); _dbus_string_free (&line); if (!retval) auth->needed_memory = TRUE; else auth->needed_memory = FALSE; return retval; } /** @} */ /** * @addtogroup DBusAuth * @{ */ /** * Creates a new auth conversation object for the server side. * See http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * for full details on what this object does. * * @returns the new object or #NULL if no memory */ DBusAuth* _dbus_auth_server_new (const DBusString *guid) { DBusAuth *auth; DBusAuthServer *server_auth; DBusString guid_copy; if (!_dbus_string_init (&guid_copy)) return NULL; if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) { _dbus_string_free (&guid_copy); return NULL; } auth = _dbus_auth_new (sizeof (DBusAuthServer)); if (auth == NULL) { _dbus_string_free (&guid_copy); return NULL; } auth->side = auth_side_server; auth->state = &server_state_waiting_for_auth; server_auth = DBUS_AUTH_SERVER (auth); server_auth->guid = guid_copy; /* perhaps this should be per-mechanism with a lower * max */ server_auth->failures = 0; server_auth->max_failures = 6; return auth; } /** * Creates a new auth conversation object for the client side. * See http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * for full details on what this object does. * * @returns the new object or #NULL if no memory */ DBusAuth* _dbus_auth_client_new (void) { DBusAuth *auth; DBusString guid_str; if (!_dbus_string_init (&guid_str)) return NULL; auth = _dbus_auth_new (sizeof (DBusAuthClient)); if (auth == NULL) { _dbus_string_free (&guid_str); return NULL; } DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; auth->side = auth_side_client; auth->state = &client_state_need_send_auth; /* Start the auth conversation by sending AUTH for our default * mechanism */ if (!send_auth (auth, &all_mechanisms[0])) { _dbus_auth_unref (auth); return NULL; } return auth; } /** * Increments the refcount of an auth object. * * @param auth the auth conversation * @returns the auth conversation */ DBusAuth * _dbus_auth_ref (DBusAuth *auth) { _dbus_assert (auth != NULL); auth->refcount += 1; return auth; } /** * Decrements the refcount of an auth object. * * @param auth the auth conversation */ void _dbus_auth_unref (DBusAuth *auth) { _dbus_assert (auth != NULL); _dbus_assert (auth->refcount > 0); auth->refcount -= 1; if (auth->refcount == 0) { shutdown_mech (auth); if (DBUS_AUTH_IS_CLIENT (auth)) { _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); } else { _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); } if (auth->keyring) _dbus_keyring_unref (auth->keyring); _dbus_string_free (&auth->context); _dbus_string_free (&auth->challenge); _dbus_string_free (&auth->identity); _dbus_string_free (&auth->incoming); _dbus_string_free (&auth->outgoing); dbus_free_string_array (auth->allowed_mechs); _dbus_credentials_unref (auth->credentials); _dbus_credentials_unref (auth->authorized_identity); _dbus_credentials_unref (auth->desired_identity); dbus_free (auth); } } /** * Sets an array of authentication mechanism names * that we are willing to use. * * @param auth the auth conversation * @param mechanisms #NULL-terminated array of mechanism names * @returns #FALSE if no memory */ dbus_bool_t _dbus_auth_set_mechanisms (DBusAuth *auth, const char **mechanisms) { char **copy; if (mechanisms != NULL) { copy = _dbus_dup_string_array (mechanisms); if (copy == NULL) return FALSE; } else copy = NULL; dbus_free_string_array (auth->allowed_mechs); auth->allowed_mechs = copy; return TRUE; } /** * @param auth the auth conversation object * @returns #TRUE if we're in a final state */ #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) /** * Analyzes buffered input and moves the auth conversation forward, * returning the new state of the auth conversation. * * @param auth the auth conversation * @returns the new state */ DBusAuthState _dbus_auth_do_work (DBusAuth *auth) { auth->needed_memory = FALSE; /* Max amount we'll buffer up before deciding someone's on crack */ #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) do { if (DBUS_AUTH_IN_END_STATE (auth)) break; if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) { goto_state (auth, &common_state_need_disconnect); _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", DBUS_AUTH_NAME (auth)); break; } } while (process_command (auth)); if (auth->needed_memory) return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; else if (_dbus_string_get_length (&auth->outgoing) > 0) return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; else if (auth->state == &common_state_need_disconnect) return DBUS_AUTH_STATE_NEED_DISCONNECT; else if (auth->state == &common_state_authenticated) return DBUS_AUTH_STATE_AUTHENTICATED; else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; } /** * Gets bytes that need to be sent to the peer we're conversing with. * After writing some bytes, _dbus_auth_bytes_sent() must be called * to notify the auth object that they were written. * * @param auth the auth conversation * @param str return location for a ref to the buffer to send * @returns #FALSE if nothing to send */ dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth, const DBusString **str) { _dbus_assert (auth != NULL); _dbus_assert (str != NULL); *str = NULL; if (_dbus_string_get_length (&auth->outgoing) == 0) return FALSE; *str = &auth->outgoing; return TRUE; } /** * Notifies the auth conversation object that * the given number of bytes of the outgoing buffer * have been written out. * * @param auth the auth conversation * @param bytes_sent number of bytes written out */ void _dbus_auth_bytes_sent (DBusAuth *auth, int bytes_sent) { _dbus_verbose ("%s: Sent %d bytes of: %s\n", DBUS_AUTH_NAME (auth), bytes_sent, _dbus_string_get_const_data (&auth->outgoing)); _dbus_string_delete (&auth->outgoing, 0, bytes_sent); } /** * Get a buffer to be used for reading bytes from the peer we're conversing * with. Bytes should be appended to this buffer. * * @param auth the auth conversation * @param buffer return location for buffer to append bytes to */ void _dbus_auth_get_buffer (DBusAuth *auth, DBusString **buffer) { _dbus_assert (auth != NULL); _dbus_assert (!auth->buffer_outstanding); *buffer = &auth->incoming; auth->buffer_outstanding = TRUE; } /** * Returns a buffer with new data read into it. * * @param auth the auth conversation * @param buffer the buffer being returned */ void _dbus_auth_return_buffer (DBusAuth *auth, DBusString *buffer) { _dbus_assert (buffer == &auth->incoming); _dbus_assert (auth->buffer_outstanding); auth->buffer_outstanding = FALSE; } /** * Returns leftover bytes that were not used as part of the auth * conversation. These bytes will be part of the message stream * instead. This function may not be called until authentication has * succeeded. * * @param auth the auth conversation * @param str return location for pointer to string of unused bytes */ void _dbus_auth_get_unused_bytes (DBusAuth *auth, const DBusString **str) { if (!DBUS_AUTH_IN_END_STATE (auth)) return; *str = &auth->incoming; } /** * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes() * after we've gotten them and successfully moved them elsewhere. * * @param auth the auth conversation */ void _dbus_auth_delete_unused_bytes (DBusAuth *auth) { if (!DBUS_AUTH_IN_END_STATE (auth)) return; _dbus_string_set_length (&auth->incoming, 0); } /** * Called post-authentication, indicates whether we need to encode * the message stream with _dbus_auth_encode_data() prior to * sending it to the peer. * * @param auth the auth conversation * @returns #TRUE if we need to encode the stream */ dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth) { if (auth->state != &common_state_authenticated) return FALSE; if (auth->mech != NULL) { if (DBUS_AUTH_IS_CLIENT (auth)) return auth->mech->client_encode_func != NULL; else return auth->mech->server_encode_func != NULL; } else return FALSE; } /** * Called post-authentication, encodes a block of bytes for sending to * the peer. If no encoding was negotiated, just copies the bytes * (you can avoid this by checking _dbus_auth_needs_encoding()). * * @param auth the auth conversation * @param plaintext the plain text data * @param encoded initialized string to where encoded data is appended * @returns #TRUE if we had enough memory and successfully encoded */ dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth, const DBusString *plaintext, DBusString *encoded) { _dbus_assert (plaintext != encoded); if (auth->state != &common_state_authenticated) return FALSE; if (_dbus_auth_needs_encoding (auth)) { if (DBUS_AUTH_IS_CLIENT (auth)) return (* auth->mech->client_encode_func) (auth, plaintext, encoded); else return (* auth->mech->server_encode_func) (auth, plaintext, encoded); } else { return _dbus_string_copy (plaintext, 0, encoded, _dbus_string_get_length (encoded)); } } /** * Called post-authentication, indicates whether we need to decode * the message stream with _dbus_auth_decode_data() after * receiving it from the peer. * * @param auth the auth conversation * @returns #TRUE if we need to encode the stream */ dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth) { if (auth->state != &common_state_authenticated) return FALSE; if (auth->mech != NULL) { if (DBUS_AUTH_IS_CLIENT (auth)) return auth->mech->client_decode_func != NULL; else return auth->mech->server_decode_func != NULL; } else return FALSE; } /** * Called post-authentication, decodes a block of bytes received from * the peer. If no encoding was negotiated, just copies the bytes (you * can avoid this by checking _dbus_auth_needs_decoding()). * * @todo 1.0? We need to be able to distinguish "out of memory" error * from "the data is hosed" error. * * @param auth the auth conversation * @param encoded the encoded data * @param plaintext initialized string where decoded data is appended * @returns #TRUE if we had enough memory and successfully decoded */ dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth, const DBusString *encoded, DBusString *plaintext) { _dbus_assert (plaintext != encoded); if (auth->state != &common_state_authenticated) return FALSE; if (_dbus_auth_needs_decoding (auth)) { if (DBUS_AUTH_IS_CLIENT (auth)) return (* auth->mech->client_decode_func) (auth, encoded, plaintext); else return (* auth->mech->server_decode_func) (auth, encoded, plaintext); } else { return _dbus_string_copy (encoded, 0, plaintext, _dbus_string_get_length (plaintext)); } } /** * Sets credentials received via reliable means from the operating * system. * * @param auth the auth conversation * @param credentials the credentials received * @returns #FALSE on OOM */ dbus_bool_t _dbus_auth_set_credentials (DBusAuth *auth, DBusCredentials *credentials) { _dbus_credentials_clear (auth->credentials); return _dbus_credentials_add_credentials (auth->credentials, credentials); } /** * Gets the identity we authorized the client as. Apps may have * different policies as to what identities they allow. * * Returned credentials are not a copy and should not be modified * * @param auth the auth conversation * @returns the credentials we've authorized BY REFERENCE do not modify */ DBusCredentials* _dbus_auth_get_identity (DBusAuth *auth) { if (auth->state == &common_state_authenticated) { return auth->authorized_identity; } else { /* FIXME instead of this, keep an empty credential around that * doesn't require allocation or something */ /* return empty credentials */ _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); return auth->authorized_identity; } } /** * Gets the GUID from the server if we've authenticated; gets * #NULL otherwise. * @param auth the auth object * @returns the GUID in ASCII hex format */ const char* _dbus_auth_get_guid_from_server (DBusAuth *auth) { _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); if (auth->state == &common_state_authenticated) return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); else return NULL; } /** * Sets the "authentication context" which scopes cookies * with the DBUS_COOKIE_SHA1 auth mechanism for example. * * @param auth the auth conversation * @param context the context * @returns #FALSE if no memory */ dbus_bool_t _dbus_auth_set_context (DBusAuth *auth, const DBusString *context) { return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), &auth->context, 0, _dbus_string_get_length (context)); } /** * Sets whether unix fd passing is potentially on the transport and * hence shall be negotiated. * * @param auth the auth conversation * @param b TRUE when unix fd passing shall be negotiated, otherwise FALSE */ void _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b) { auth->unix_fd_possible = b; } /** * Queries whether unix fd passing was successfully negotiated. * * @param auth the auth conversion * @returns #TRUE when unix fd passing was negotiated. */ dbus_bool_t _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth) { return auth->unix_fd_negotiated; } /** @} */ /* tests in dbus-auth-util.c */ dbus-1.10.6/dbus/dbus-address.c0000644000175000017500000005064312602773110016226 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-address.c Server address parser. * * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2004,2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "dbus-address.h" #include "dbus-internals.h" #include "dbus-list.h" #include "dbus-string.h" #include "dbus-protocol.h" /** * @defgroup DBusAddressInternals Address parsing * @ingroup DBusInternals * @brief Implementation of parsing addresses of D-Bus servers. * * @{ */ /** * Internals of DBusAddressEntry */ struct DBusAddressEntry { DBusString method; /**< The address type (unix, tcp, etc.) */ DBusList *keys; /**< List of keys */ DBusList *values; /**< List of values */ }; /** * * Sets #DBUS_ERROR_BAD_ADDRESS. * If address_problem_type and address_problem_field are not #NULL, * sets an error message about how the field is no good. Otherwise, sets * address_problem_other as the error message. * * @param error the error to set * @param address_problem_type the address type of the bad address or #NULL * @param address_problem_field the missing field of the bad address or #NULL * @param address_problem_other any other error message or #NULL */ void _dbus_set_bad_address (DBusError *error, const char *address_problem_type, const char *address_problem_field, const char *address_problem_other) { if (address_problem_type != NULL) dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Server address of type %s was missing argument %s", address_problem_type, address_problem_field); else dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Could not parse server address: %s", address_problem_other); } /** * #TRUE if the byte need not be escaped when found in a dbus address. * All other bytes are required to be escaped in a valid address. */ #define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \ (((b) >= 'a' && (b) <= 'z') || \ ((b) >= 'A' && (b) <= 'Z') || \ ((b) >= '0' && (b) <= '9') || \ (b) == '-' || \ (b) == '_' || \ (b) == '/' || \ (b) == '\\' || \ (b) == '*' || \ (b) == '.') /** * Appends an escaped version of one string to another string, * using the D-Bus address escaping mechanism * * @param escaped the string to append to * @param unescaped the string to escape * @returns #FALSE if no memory */ dbus_bool_t _dbus_address_append_escaped (DBusString *escaped, const DBusString *unescaped) { const unsigned char *p; const unsigned char *end; dbus_bool_t ret; int orig_len; ret = FALSE; orig_len = _dbus_string_get_length (escaped); p = (const unsigned char *) _dbus_string_get_const_data (unescaped); end = p + _dbus_string_get_length (unescaped); while (p != end) { if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p)) { if (!_dbus_string_append_byte (escaped, *p)) goto out; } else { if (!_dbus_string_append_byte (escaped, '%')) goto out; if (!_dbus_string_append_byte_as_hex (escaped, *p)) goto out; } ++p; } ret = TRUE; out: if (!ret) _dbus_string_set_length (escaped, orig_len); return ret; } /** @} */ /* End of internals */ static void dbus_address_entry_free (DBusAddressEntry *entry) { DBusList *link; _dbus_string_free (&entry->method); link = _dbus_list_get_first_link (&entry->keys); while (link != NULL) { _dbus_string_free (link->data); dbus_free (link->data); link = _dbus_list_get_next_link (&entry->keys, link); } _dbus_list_clear (&entry->keys); link = _dbus_list_get_first_link (&entry->values); while (link != NULL) { _dbus_string_free (link->data); dbus_free (link->data); link = _dbus_list_get_next_link (&entry->values, link); } _dbus_list_clear (&entry->values); dbus_free (entry); } /** * @defgroup DBusAddress Address parsing * @ingroup DBus * @brief Parsing addresses of D-Bus servers. * * @{ */ /** * Frees a #NULL-terminated array of address entries. * * @param entries the array. */ void dbus_address_entries_free (DBusAddressEntry **entries) { int i; for (i = 0; entries[i] != NULL; i++) dbus_address_entry_free (entries[i]); dbus_free (entries); } static DBusAddressEntry * create_entry (void) { DBusAddressEntry *entry; entry = dbus_new0 (DBusAddressEntry, 1); if (entry == NULL) return NULL; if (!_dbus_string_init (&entry->method)) { dbus_free (entry); return NULL; } return entry; } /** * Returns the method string of an address entry. For example, given * the address entry "tcp:host=example.com" it would return the string * "tcp" * * @param entry the entry. * @returns a string describing the method. This string * must not be freed. */ const char * dbus_address_entry_get_method (DBusAddressEntry *entry) { return _dbus_string_get_const_data (&entry->method); } /** * Returns a value from a key of an entry. For example, * given the address "tcp:host=example.com,port=8073" if you asked * for the key "host" you would get the value "example.com" * * The returned value is already unescaped. * * @param entry the entry. * @param key the key. * @returns the key value. This string must not be freed. */ const char * dbus_address_entry_get_value (DBusAddressEntry *entry, const char *key) { DBusList *values, *keys; keys = _dbus_list_get_first_link (&entry->keys); values = _dbus_list_get_first_link (&entry->values); while (keys != NULL) { _dbus_assert (values != NULL); if (_dbus_string_equal_c_str (keys->data, key)) return _dbus_string_get_const_data (values->data); keys = _dbus_list_get_next_link (&entry->keys, keys); values = _dbus_list_get_next_link (&entry->values, values); } return NULL; } static dbus_bool_t append_unescaped_value (DBusString *unescaped, const DBusString *escaped, int escaped_start, int escaped_len, DBusError *error) { const char *p; const char *end; dbus_bool_t ret; ret = FALSE; p = _dbus_string_get_const_data (escaped) + escaped_start; end = p + escaped_len; while (p != end) { if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p)) { if (!_dbus_string_append_byte (unescaped, *p)) goto out; } else if (*p == '%') { /* Efficiency is king */ char buf[3]; DBusString hex; int hex_end; ++p; if ((p + 2) > end) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "In D-Bus address, percent character was not followed by two hex digits"); goto out; } buf[0] = *p; ++p; buf[1] = *p; buf[2] = '\0'; _dbus_string_init_const (&hex, buf); if (!_dbus_string_hex_decode (&hex, 0, &hex_end, unescaped, _dbus_string_get_length (unescaped))) goto out; if (hex_end != 2) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "In D-Bus address, percent character was followed by characters other than hex digits"); goto out; } } else { /* Error, should have been escaped */ dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "In D-Bus address, character '%c' should have been escaped\n", *p); goto out; } ++p; } ret = TRUE; out: if (!ret && error && !dbus_error_is_set (error)) _DBUS_SET_OOM (error); _dbus_assert (ret || error == NULL || dbus_error_is_set (error)); return ret; } /** * Parses an address string of the form: * * method:key=value,key=value;method:key=value * * See the D-Bus specification for complete docs on the format. * * When connecting to an address, the first address entries * in the semicolon-separated list should be tried first. * * @param address the address. * @param entry return location to an array of entries. * @param array_len return location for array length. * @param error address where an error can be returned. * @returns #TRUE on success, #FALSE otherwise. */ dbus_bool_t dbus_parse_address (const char *address, DBusAddressEntry ***entry, int *array_len, DBusError *error) { DBusString str; int pos, end_pos, len, i; DBusList *entries, *link; DBusAddressEntry **entry_array; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_string_init_const (&str, address); entries = NULL; pos = 0; len = _dbus_string_get_length (&str); if (len == 0) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Empty address '%s'", address); goto error; } while (pos < len) { DBusAddressEntry *entry; int found_pos; entry = create_entry (); if (!entry) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto error; } /* Append the entry */ if (!_dbus_list_append (&entries, entry)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_address_entry_free (entry); goto error; } /* Look for a semi-colon */ if (!_dbus_string_find (&str, pos, ";", &end_pos)) end_pos = len; /* Look for the colon : */ if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos)) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon"); goto error; } if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto error; } pos = found_pos + 1; while (pos < end_pos) { int comma_pos, equals_pos; if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos)) comma_pos = end_pos; if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) || equals_pos == pos || equals_pos + 1 == comma_pos) { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "'=' character not found or has no value following it"); goto error; } else { DBusString *key; DBusString *value; key = dbus_new0 (DBusString, 1); if (!key) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto error; } value = dbus_new0 (DBusString, 1); if (!value) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_free (key); goto error; } if (!_dbus_string_init (key)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); dbus_free (key); dbus_free (value); goto error; } if (!_dbus_string_init (value)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (key); dbus_free (key); dbus_free (value); goto error; } if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (key); _dbus_string_free (value); dbus_free (key); dbus_free (value); goto error; } if (!append_unescaped_value (value, &str, equals_pos + 1, comma_pos - equals_pos - 1, error)) { _dbus_assert (error == NULL || dbus_error_is_set (error)); _dbus_string_free (key); _dbus_string_free (value); dbus_free (key); dbus_free (value); goto error; } if (!_dbus_list_append (&entry->keys, key)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (key); _dbus_string_free (value); dbus_free (key); dbus_free (value); goto error; } if (!_dbus_list_append (&entry->values, value)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (value); dbus_free (value); goto error; } } pos = comma_pos + 1; } pos = end_pos + 1; } *array_len = _dbus_list_get_length (&entries); entry_array = dbus_new (DBusAddressEntry *, *array_len + 1); if (!entry_array) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto error; } entry_array [*array_len] = NULL; link = _dbus_list_get_first_link (&entries); i = 0; while (link != NULL) { entry_array[i] = link->data; i++; link = _dbus_list_get_next_link (&entries, link); } _dbus_list_clear (&entries); *entry = entry_array; return TRUE; error: link = _dbus_list_get_first_link (&entries); while (link != NULL) { dbus_address_entry_free (link->data); link = _dbus_list_get_next_link (&entries, link); } _dbus_list_clear (&entries); return FALSE; } /** * Escapes the given string as a value in a key=value pair * for a D-Bus address. * * @param value the unescaped value * @returns newly-allocated escaped value or #NULL if no memory */ char* dbus_address_escape_value (const char *value) { DBusString escaped; DBusString unescaped; char *ret; ret = NULL; _dbus_string_init_const (&unescaped, value); if (!_dbus_string_init (&escaped)) return NULL; if (!_dbus_address_append_escaped (&escaped, &unescaped)) goto out; if (!_dbus_string_steal_data (&escaped, &ret)) goto out; out: _dbus_string_free (&escaped); return ret; } /** * Unescapes the given string as a value in a key=value pair * for a D-Bus address. Note that dbus_address_entry_get_value() * returns an already-unescaped value. * * @param value the escaped value * @param error error to set if the unescaping fails * @returns newly-allocated unescaped value or #NULL if no memory */ char* dbus_address_unescape_value (const char *value, DBusError *error) { DBusString unescaped; DBusString escaped; char *ret; ret = NULL; _dbus_string_init_const (&escaped, value); if (!_dbus_string_init (&unescaped)) return NULL; if (!append_unescaped_value (&unescaped, &escaped, 0, _dbus_string_get_length (&escaped), error)) goto out; if (!_dbus_string_steal_data (&unescaped, &ret)) goto out; out: if (ret == NULL && error && !dbus_error_is_set (error)) _DBUS_SET_OOM (error); _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error)); _dbus_string_free (&unescaped); return ret; } /** @} */ /* End of public API */ #ifdef DBUS_ENABLE_EMBEDDED_TESTS #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "dbus-test.h" #include typedef struct { const char *escaped; const char *unescaped; } EscapeTest; static const EscapeTest escape_tests[] = { { "abcde", "abcde" }, { "", "" }, { "%20%20", " " }, { "%24", "$" }, { "%25", "%" }, { "abc%24", "abc$" }, { "%24abc", "$abc" }, { "abc%24abc", "abc$abc" }, { "/", "/" }, { "-", "-" }, { "_", "_" }, { "A", "A" }, { "I", "I" }, { "Z", "Z" }, { "a", "a" }, { "i", "i" }, { "z", "z" }, /* Bug: https://bugs.freedesktop.org/show_bug.cgi?id=53499 */ { "%c3%b6", "\xc3\xb6" } }; static const char* invalid_escaped_values[] = { "%a", "%q", "%az", "%%", "%$$", "abc%a", "%axyz", "%", "$", " ", }; dbus_bool_t _dbus_address_test (void) { DBusAddressEntry **entries; int len; DBusError error = DBUS_ERROR_INIT; int i; i = 0; while (i < _DBUS_N_ELEMENTS (escape_tests)) { const EscapeTest *test = &escape_tests[i]; char *escaped; char *unescaped; escaped = dbus_address_escape_value (test->unescaped); if (escaped == NULL) _dbus_assert_not_reached ("oom"); if (strcmp (escaped, test->escaped) != 0) { _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n", test->unescaped, escaped, test->escaped); exit (1); } dbus_free (escaped); unescaped = dbus_address_unescape_value (test->escaped, &error); if (unescaped == NULL) { _dbus_warn ("Failed to unescape '%s': %s\n", test->escaped, error.message); dbus_error_free (&error); exit (1); } if (strcmp (unescaped, test->unescaped) != 0) { _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n", test->escaped, unescaped, test->unescaped); exit (1); } dbus_free (unescaped); ++i; } i = 0; while (i < _DBUS_N_ELEMENTS (invalid_escaped_values)) { char *unescaped; unescaped = dbus_address_unescape_value (invalid_escaped_values[i], &error); if (unescaped != NULL) { _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n", invalid_escaped_values[i], unescaped); dbus_free (unescaped); exit (1); } _dbus_assert (dbus_error_is_set (&error)); dbus_error_free (&error); ++i; } if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;", &entries, &len, &error)) _dbus_assert_not_reached ("could not parse address"); _dbus_assert (len == 2); _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0); _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0); _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0); dbus_address_entries_free (entries); /* Different possible errors */ if (dbus_parse_address ("", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:bar", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:=foo", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:foo=", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error)) _dbus_assert_not_reached ("Parsed incorrect address."); else dbus_error_free (&error); return TRUE; } #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ #endif dbus-1.10.6/dbus/versioninfo.rc.in0000644000175000017500000000316012602773110016766 0ustar00smcvsmcv00000000000000/* versioninfo.rc.in - for dbus * Copyright (C) 2005 g10 Code GmbH * * This file is free software; as a special exception the author gives * unlimited permission to copy and/or distribute it, with or without * modifications, as long as this notice is preserved. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* This file is processed by configure to create versioninfo.rc */ #line __LINE__ "versioninfo.rc.in" #include VS_VERSION_INFO VERSIONINFO FILEVERSION @BUILD_FILEVERSION@ PRODUCTVERSION @BUILD_FILEVERSION@ FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x21L #else FILEFLAGS 0x20L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "Provided under the terms of the GNU Lesser General Public License.\0" VALUE "CompanyName", "FreeDesktop.org\0" VALUE "FileDescription", "dbus - FreeDesktop message bus system\0" VALUE "FileVersion", "@DBUS_VERSION@\0" VALUE "InternalName", "dbus\0" VALUE "LegalCopyright", "Copyright 2009 FreeDesktop.org\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "dbus-1.dll\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "dbus\0" VALUE "ProductVersion", "@DBUS_VERSION@\0" VALUE "SpecialBuild", "@BUILD_TIMESTAMP@\0" END END END dbus-1.10.6/dbus/dbus-arch-deps.h.in0000644000175000017500000000434112602773110017053 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-arch-deps.h Header with architecture/compiler specific information, installed to libdir * * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 2.0 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_ARCH_DEPS_H #define DBUS_ARCH_DEPS_H #include DBUS_BEGIN_DECLS /* D-Bus no longer supports platforms with no 64-bit integer type. */ #define DBUS_HAVE_INT64 1 _DBUS_GNUC_EXTENSION typedef @DBUS_INT64_TYPE@ dbus_int64_t; _DBUS_GNUC_EXTENSION typedef unsigned @DBUS_INT64_TYPE@ dbus_uint64_t; #define DBUS_INT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION @DBUS_INT64_CONSTANT@) #define DBUS_UINT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION @DBUS_UINT64_CONSTANT@) typedef @DBUS_INT32_TYPE@ dbus_int32_t; typedef unsigned @DBUS_INT32_TYPE@ dbus_uint32_t; typedef @DBUS_INT16_TYPE@ dbus_int16_t; typedef unsigned @DBUS_INT16_TYPE@ dbus_uint16_t; /* This is not really arch-dependent, but it's not worth * creating an additional generated header just for this */ #define DBUS_MAJOR_VERSION @DBUS_MAJOR_VERSION@ #define DBUS_MINOR_VERSION @DBUS_MINOR_VERSION@ #define DBUS_MICRO_VERSION @DBUS_MICRO_VERSION@ #define DBUS_VERSION_STRING "@DBUS_VERSION@" #define DBUS_VERSION ((@DBUS_MAJOR_VERSION@ << 16) | (@DBUS_MINOR_VERSION@ << 8) | (@DBUS_MICRO_VERSION@)) DBUS_END_DECLS #endif /* DBUS_ARCH_DEPS_H */ dbus-1.10.6/dbus/Version.in0000644000175000017500000000017412602773110015451 0ustar00smcvsmcv00000000000000LIBDBUS_1_@SOVERSION@ { global: dbus_*; local: *; }; LIBDBUS_PRIVATE_@DBUS_VERSION@ { global: _dbus_*; }; dbus-1.10.6/dbus/Makefile.in0000644000175000017500000034301012627362261015550 0ustar00smcvsmcv00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @DBUS_WIN_FALSE@@HAVE_VISIBILITY_TRUE@am__append_1 = $(CFLAG_VISIBILITY) @DBUS_WIN_FALSE@@HAVE_VISIBILITY_TRUE@am__append_2 = \ @DBUS_WIN_FALSE@@HAVE_VISIBILITY_TRUE@ -DDBUS_EXPORT='__attribute__((__visibility__("default")))' \ @DBUS_WIN_FALSE@@HAVE_VISIBILITY_TRUE@ -DDBUS_PRIVATE_EXPORT='__attribute__((__visibility__("default")))' \ @DBUS_WIN_FALSE@@HAVE_VISIBILITY_TRUE@ $(NULL) @HAVE_LINUX_EPOLL_TRUE@am__append_3 = dbus-socket-set-epoll.c # This must be a separate convenience library, otherwise libtool notices # that libdbus-1 might contain C++, links it with g++ and links in libstdc++, # even on Unix where in fact it doesn't contain any C++. For Windows, where # this code is used, we don't actually need libstdc++. @DBUS_WIN_TRUE@am__append_4 = libdbus-init-win.la @DBUS_WIN_TRUE@am__append_5 = libdbus-init-win.la noinst_PROGRAMS = $(am__EXEEXT_1) # We can't actually run this til we've reached test/ @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@am__append_6 = test-dbus subdir = dbus ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ $(top_srcdir)/m4/compiler.m4 \ $(top_srcdir)/m4/ld-version-script.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/m4/tp-compiler-flag.m4 \ $(top_srcdir)/m4/tp-compiler-warnings.m4 \ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dbusinclude_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = Version versioninfo.rc dbus-arch-deps.h CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(dbusincludedir)" \ "$(DESTDIR)$(dbusarchincludedir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = libdbus_1_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__append_5) am__libdbus_1_la_SOURCES_DIST = dbus-address.c dbus-auth.c dbus-auth.h \ dbus-bus.c dbus-connection.c dbus-connection-internal.h \ dbus-credentials.c dbus-credentials.h dbus-errors.c \ dbus-keyring.c dbus-keyring.h dbus-marshal-header.c \ dbus-marshal-header.h dbus-marshal-byteswap.c \ dbus-marshal-byteswap.h dbus-marshal-recursive.c \ dbus-marshal-recursive.h dbus-marshal-validate.c \ dbus-marshal-validate.h dbus-message.c dbus-message-internal.h \ dbus-message-private.h dbus-misc.c dbus-nonce.h dbus-nonce.c \ dbus-object-tree.c dbus-object-tree.h dbus-pending-call.c \ dbus-pending-call-internal.h dbus-resources.c dbus-resources.h \ dbus-server.c dbus-server-debug-pipe.c \ dbus-server-debug-pipe.h dbus-server-protected.h \ dbus-server-socket.c dbus-server-socket.h dbus-uuidgen.c \ dbus-uuidgen.h dbus-server-unix.c dbus-server-unix.h \ dbus-server-win.c dbus-server-win.h dbus-sha.c dbus-sha.h \ dbus-signature.c dbus-syntax.c dbus-timeout.c dbus-timeout.h \ dbus-threads-internal.h dbus-threads.c dbus-transport.c \ dbus-transport.h dbus-transport-protected.h \ dbus-transport-socket.c dbus-transport-socket.h dbus-watch.c \ dbus-watch.h dbus-dataslot.c dbus-dataslot.h dbus-file.c \ dbus-file.h dbus-hash.c dbus-hash.h dbus-internals.c \ dbus-internals.h dbus-list.c dbus-list.h dbus-marshal-basic.c \ dbus-marshal-basic.h dbus-memory.c dbus-mempool.c \ dbus-mempool.h dbus-pipe.c dbus-pipe.h dbus-string.c \ dbus-string.h dbus-string-private.h dbus-server-launchd.h \ dbus-server-launchd.c dbus-file-unix.c dbus-pipe-unix.c \ dbus-sysdeps-unix.c dbus-sysdeps-unix.h dbus-sysdeps-pthread.c \ dbus-transport-unix.c dbus-transport-unix.h dbus-userdb.c \ dbus-userdb.h dbus-sysdeps-wince-glue.h \ dbus-sysdeps-wince-glue.c dbus-file-win.c dbus-pipe-win.c \ dbus-sockets-win.h dbus-sysdeps-win.c dbus-sysdeps-win.h \ dbus-sysdeps-thread-win.c dbus-transport-win.c \ dbus-transport-win.h dbus-sysdeps.c dbus-sysdeps.h \ dbus-valgrind-internal.h @DBUS_WIN_FALSE@am__objects_1 = libdbus_1_la-dbus-uuidgen.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-server-unix.lo @DBUS_WIN_TRUE@am__objects_1 = libdbus_1_la-dbus-server-win.lo am__objects_2 = libdbus_1_la-dbus-address.lo libdbus_1_la-dbus-auth.lo \ libdbus_1_la-dbus-bus.lo libdbus_1_la-dbus-connection.lo \ libdbus_1_la-dbus-credentials.lo libdbus_1_la-dbus-errors.lo \ libdbus_1_la-dbus-keyring.lo \ libdbus_1_la-dbus-marshal-header.lo \ libdbus_1_la-dbus-marshal-byteswap.lo \ libdbus_1_la-dbus-marshal-recursive.lo \ libdbus_1_la-dbus-marshal-validate.lo \ libdbus_1_la-dbus-message.lo libdbus_1_la-dbus-misc.lo \ libdbus_1_la-dbus-nonce.lo libdbus_1_la-dbus-object-tree.lo \ libdbus_1_la-dbus-pending-call.lo \ libdbus_1_la-dbus-resources.lo libdbus_1_la-dbus-server.lo \ libdbus_1_la-dbus-server-debug-pipe.lo \ libdbus_1_la-dbus-server-socket.lo $(am__objects_1) \ libdbus_1_la-dbus-sha.lo libdbus_1_la-dbus-signature.lo \ libdbus_1_la-dbus-syntax.lo libdbus_1_la-dbus-timeout.lo \ libdbus_1_la-dbus-threads.lo libdbus_1_la-dbus-transport.lo \ libdbus_1_la-dbus-transport-socket.lo \ libdbus_1_la-dbus-watch.lo @DBUS_ENABLE_LAUNCHD_TRUE@@DBUS_WIN_FALSE@am__objects_3 = libdbus_1_la-dbus-server-launchd.lo @DBUS_WINCE_TRUE@@DBUS_WIN_TRUE@am__objects_4 = libdbus_1_la-dbus-sysdeps-wince-glue.lo @DBUS_WIN_FALSE@am__objects_5 = $(am__objects_3) \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-file-unix.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-pipe-unix.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-sysdeps-unix.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-sysdeps-pthread.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-transport-unix.lo \ @DBUS_WIN_FALSE@ libdbus_1_la-dbus-userdb.lo @DBUS_WIN_TRUE@am__objects_5 = $(am__objects_4) \ @DBUS_WIN_TRUE@ libdbus_1_la-dbus-file-win.lo \ @DBUS_WIN_TRUE@ libdbus_1_la-dbus-pipe-win.lo \ @DBUS_WIN_TRUE@ libdbus_1_la-dbus-sysdeps-win.lo \ @DBUS_WIN_TRUE@ libdbus_1_la-dbus-sysdeps-thread-win.lo \ @DBUS_WIN_TRUE@ libdbus_1_la-dbus-transport-win.lo am__objects_6 = libdbus_1_la-dbus-dataslot.lo \ libdbus_1_la-dbus-file.lo libdbus_1_la-dbus-hash.lo \ libdbus_1_la-dbus-internals.lo libdbus_1_la-dbus-list.lo \ libdbus_1_la-dbus-marshal-basic.lo libdbus_1_la-dbus-memory.lo \ libdbus_1_la-dbus-mempool.lo libdbus_1_la-dbus-pipe.lo \ libdbus_1_la-dbus-string.lo $(am__objects_5) \ libdbus_1_la-dbus-sysdeps.lo am_libdbus_1_la_OBJECTS = $(am__objects_2) $(am__objects_6) libdbus_1_la_OBJECTS = $(am_libdbus_1_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libdbus_1_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libdbus_1_la_LDFLAGS) $(LDFLAGS) -o $@ libdbus_init_win_la_LIBADD = am__libdbus_init_win_la_SOURCES_DIST = dbus-init-win.cpp @DBUS_WIN_TRUE@am_libdbus_init_win_la_OBJECTS = dbus-init-win.lo libdbus_init_win_la_OBJECTS = $(am_libdbus_init_win_la_OBJECTS) @DBUS_WIN_TRUE@am_libdbus_init_win_la_rpath = libdbus_internal_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libdbus-1.la am__libdbus_internal_la_SOURCES_DIST = dbus-asv-util.c dbus-asv-util.h \ dbus-auth-script.c dbus-auth-script.h dbus-auth-util.c \ dbus-credentials-util.c dbus-mainloop.c dbus-mainloop.h \ dbus-marshal-byteswap-util.c dbus-marshal-recursive-util.c \ dbus-marshal-validate-util.c dbus-message-factory.c \ dbus-message-factory.h dbus-message-util.c dbus-shell.c \ dbus-shell.h dbus-sysdeps-util-unix.c dbus-userdb-util.c \ dbus-spawn.c dbus-socket-set-epoll.c dbus-sysdeps-util-win.c \ dbus-spawn-win.c dbus-socket-set.h dbus-socket-set.c \ dbus-socket-set-poll.c dbus-spawn.h dbus-string-util.c \ dbus-sysdeps-util.c dbus-test.c dbus-test.h @HAVE_LINUX_EPOLL_TRUE@am__objects_7 = dbus-socket-set-epoll.lo @DBUS_WIN_FALSE@am__objects_8 = dbus-sysdeps-util-unix.lo \ @DBUS_WIN_FALSE@ dbus-userdb-util.lo dbus-spawn.lo \ @DBUS_WIN_FALSE@ $(am__objects_7) @DBUS_WIN_TRUE@am__objects_8 = dbus-sysdeps-util-win.lo \ @DBUS_WIN_TRUE@ dbus-spawn-win.lo $(am__objects_7) am__objects_9 = dbus-asv-util.lo dbus-auth-script.lo dbus-auth-util.lo \ dbus-credentials-util.lo dbus-mainloop.lo \ dbus-marshal-byteswap-util.lo dbus-marshal-recursive-util.lo \ dbus-marshal-validate-util.lo dbus-message-factory.lo \ dbus-message-util.lo dbus-shell.lo $(am__objects_8) \ dbus-socket-set.lo dbus-socket-set-poll.lo dbus-string-util.lo \ dbus-sysdeps-util.lo dbus-test.lo am_libdbus_internal_la_OBJECTS = $(am__objects_9) libdbus_internal_la_OBJECTS = $(am_libdbus_internal_la_OBJECTS) @DBUS_ENABLE_EMBEDDED_TESTS_TRUE@am__EXEEXT_1 = test-dbus$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) am_test_dbus_OBJECTS = dbus-test-main.$(OBJEXT) test_dbus_OBJECTS = $(am_test_dbus_OBJECTS) test_dbus_DEPENDENCIES = libdbus-internal.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libdbus_1_la_SOURCES) $(libdbus_init_win_la_SOURCES) \ $(libdbus_internal_la_SOURCES) $(test_dbus_SOURCES) DIST_SOURCES = $(am__libdbus_1_la_SOURCES_DIST) \ $(am__libdbus_init_win_la_SOURCES_DIST) \ $(am__libdbus_internal_la_SOURCES_DIST) $(test_dbus_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(dbusinclude_HEADERS) $(nodist_dbusarchinclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Version.in \ $(srcdir)/dbus-arch-deps.h.in $(srcdir)/versioninfo.rc.in \ $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ADT_LIBS = @ADT_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPARMOR_CFLAGS = @APPARMOR_CFLAGS@ APPARMOR_LIBS = @APPARMOR_LIBS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FILEVERSION = @BUILD_FILEVERSION@ BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIR_FROM_PKGSYSCONFDIR = @DATADIR_FROM_PKGSYSCONFDIR@ DBUS_BINDIR = @DBUS_BINDIR@ DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ DBUS_DATADIR = @DBUS_DATADIR@ DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ DBUS_PREFIX = @DBUS_PREFIX@ DBUS_SESSION_BUS_CONNECT_ADDRESS = @DBUS_SESSION_BUS_CONNECT_ADDRESS@ DBUS_SESSION_BUS_LISTEN_ADDRESS = @DBUS_SESSION_BUS_LISTEN_ADDRESS@ DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL = @DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL@ DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ DBUS_STATIC_BUILD_CPPFLAGS = @DBUS_STATIC_BUILD_CPPFLAGS@ DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ DBUS_TEST_DATA = @DBUS_TEST_DATA@ DBUS_TEST_EXEC = @DBUS_TEST_EXEC@ DBUS_TEST_USER = @DBUS_TEST_USER@ DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ DBUS_USER = @DBUS_USER@ DBUS_VERSION = @DBUS_VERSION@ DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ DBUS_X_LIBS = @DBUS_X_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUCKTYPE = @DUCKTYPE@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXPANDED_BINDIR = @EXPANDED_BINDIR@ EXPANDED_DATADIR = @EXPANDED_DATADIR@ EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ EXPANDED_PREFIX = @EXPANDED_PREFIX@ EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GREP = @GREP@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LAUNCHCTL = @LAUNCHCTL@ LAUNCHD_AGENT_DIR = @LAUNCHD_AGENT_DIR@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBDBUS_LIBS = @LIBDBUS_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ LT_REVISION = @LT_REVISION@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETWORK_libs = @NETWORK_libs@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RC = @RC@ R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ SED = @SED@ SELINUX_LIBS = @SELINUX_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOVERSION = @SOVERSION@ STRIP = @STRIP@ SYSCONFDIR_FROM_PKGDATADIR = @SYSCONFDIR_FROM_PKGDATADIR@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ SYSTEMD_LIBS = @SYSTEMD_LIBS@ TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ TEST_LISTEN = @TEST_LISTEN@ TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ THREAD_LIBS = @THREAD_LIBS@ VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ VALGRIND_LIBS = @VALGRIND_LIBS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XMKMF = @XMKMF@ XMLTO = @XMLTO@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ XSLTPROC = @XSLTPROC@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ YELP_BUILD = @YELP_BUILD@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ dbus_daemondir = @dbus_daemondir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemduserunitdir = @systemduserunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dbusdatadir = $(datadir)/dbus-1 AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) $(SYSTEMD_CFLAGS) \ $(VALGRIND_CFLAGS) -DDBUS_COMPILATION \ -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \ -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \ -DDBUS_SESSION_CONFIG_FILE=\""$(dbusdatadir)/session.conf"\" \ $(NULL) $(am__append_2) AM_CFLAGS = $(am__append_1) # if assertions are enabled, improve backtraces AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ dbusincludedir = $(includedir)/dbus-1.0/dbus dbusarchincludedir = $(libdir)/dbus-1.0/include/dbus lib_LTLIBRARIES = libdbus-1.la # # Deal with W32 .def and version-info.rc stuff # @DBUS_WIN_TRUE@SUFFIXES = rc @DBUS_WIN_FALSE@dbus_res = @DBUS_WIN_TRUE@dbus_res = versioninfo.o @DBUS_WIN_FALSE@dbus_res_ldflag = @DBUS_WIN_TRUE@dbus_res_ldflag = -Wl,$(dbus_res) @DBUS_WIN_FALSE@no_undefined = @DBUS_WIN_TRUE@no_undefined = -no-undefined @DBUS_WIN_TRUE@export_symbols = @DBUS_WIN_TRUE@EXTRA_libdbus_1_la_DEPENDENCIES = $(dbus_res) @DBUS_WIN_FALSE@intllibs = @LTLIBINTL@ @DBUS_WIN_TRUE@intllibs = @DBUS_WIN_FALSE@DBUS_LIB_arch_sources = \ @DBUS_WIN_FALSE@ dbus-uuidgen.c \ @DBUS_WIN_FALSE@ dbus-uuidgen.h \ @DBUS_WIN_FALSE@ dbus-server-unix.c \ @DBUS_WIN_FALSE@ dbus-server-unix.h # # Platform-dependent sources: # @DBUS_WIN_TRUE@DBUS_LIB_arch_sources = \ @DBUS_WIN_TRUE@ dbus-server-win.c \ @DBUS_WIN_TRUE@ dbus-server-win.h @DBUS_WINCE_FALSE@@DBUS_WIN_TRUE@wince_source = @DBUS_WINCE_TRUE@@DBUS_WIN_TRUE@wince_source = dbus-sysdeps-wince-glue.h dbus-sysdeps-wince-glue.c @DBUS_WIN_FALSE@DBUS_SHARED_arch_sources = \ @DBUS_WIN_FALSE@ $(launchd_source) \ @DBUS_WIN_FALSE@ dbus-file-unix.c \ @DBUS_WIN_FALSE@ dbus-pipe-unix.c \ @DBUS_WIN_FALSE@ dbus-sysdeps-unix.c \ @DBUS_WIN_FALSE@ dbus-sysdeps-unix.h \ @DBUS_WIN_FALSE@ dbus-sysdeps-pthread.c \ @DBUS_WIN_FALSE@ dbus-transport-unix.c \ @DBUS_WIN_FALSE@ dbus-transport-unix.h \ @DBUS_WIN_FALSE@ dbus-userdb.c \ @DBUS_WIN_FALSE@ dbus-userdb.h \ @DBUS_WIN_FALSE@ $(NULL) @DBUS_WIN_TRUE@DBUS_SHARED_arch_sources = \ @DBUS_WIN_TRUE@ $(wince_source) \ @DBUS_WIN_TRUE@ dbus-file-win.c \ @DBUS_WIN_TRUE@ dbus-pipe-win.c \ @DBUS_WIN_TRUE@ dbus-sockets-win.h \ @DBUS_WIN_TRUE@ dbus-sysdeps-win.c \ @DBUS_WIN_TRUE@ dbus-sysdeps-win.h \ @DBUS_WIN_TRUE@ dbus-sysdeps-thread-win.c \ @DBUS_WIN_TRUE@ dbus-transport-win.c \ @DBUS_WIN_TRUE@ dbus-transport-win.h @DBUS_WIN_FALSE@DBUS_UTIL_arch_sources = dbus-sysdeps-util-unix.c \ @DBUS_WIN_FALSE@ dbus-userdb-util.c dbus-spawn.c \ @DBUS_WIN_FALSE@ $(am__append_3) @DBUS_WIN_TRUE@DBUS_UTIL_arch_sources = dbus-sysdeps-util-win.c \ @DBUS_WIN_TRUE@ dbus-spawn-win.c $(am__append_3) @DBUS_ENABLE_LAUNCHD_FALSE@@DBUS_WIN_FALSE@launchd_source = @DBUS_ENABLE_LAUNCHD_TRUE@@DBUS_WIN_FALSE@launchd_source = dbus-server-launchd.h dbus-server-launchd.c dbusinclude_HEADERS = \ dbus.h \ dbus-address.h \ dbus-bus.h \ dbus-connection.h \ dbus-errors.h \ dbus-macros.h \ dbus-memory.h \ dbus-message.h \ dbus-misc.h \ dbus-pending-call.h \ dbus-protocol.h \ dbus-server.h \ dbus-shared.h \ dbus-signature.h \ dbus-syntax.h \ dbus-threads.h \ dbus-types.h nodist_dbusarchinclude_HEADERS = \ dbus-arch-deps.h ### source code that goes in the installed client library ### and is specific to library functionality DBUS_LIB_SOURCES = \ dbus-address.c \ dbus-auth.c \ dbus-auth.h \ dbus-bus.c \ dbus-connection.c \ dbus-connection-internal.h \ dbus-credentials.c \ dbus-credentials.h \ dbus-errors.c \ dbus-keyring.c \ dbus-keyring.h \ dbus-marshal-header.c \ dbus-marshal-header.h \ dbus-marshal-byteswap.c \ dbus-marshal-byteswap.h \ dbus-marshal-recursive.c \ dbus-marshal-recursive.h \ dbus-marshal-validate.c \ dbus-marshal-validate.h \ dbus-message.c \ dbus-message-internal.h \ dbus-message-private.h \ dbus-misc.c \ dbus-nonce.h \ dbus-nonce.c \ dbus-object-tree.c \ dbus-object-tree.h \ dbus-pending-call.c \ dbus-pending-call-internal.h \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ dbus-server-debug-pipe.c \ dbus-server-debug-pipe.h \ dbus-server-protected.h \ dbus-server-socket.c \ dbus-server-socket.h \ $(DBUS_LIB_arch_sources) \ dbus-sha.c \ dbus-sha.h \ dbus-signature.c \ dbus-syntax.c \ dbus-timeout.c \ dbus-timeout.h \ dbus-threads-internal.h \ dbus-threads.c \ dbus-transport.c \ dbus-transport.h \ dbus-transport-protected.h \ dbus-transport-socket.c \ dbus-transport-socket.h \ dbus-watch.c \ dbus-watch.h ### source code that goes in the installed client library ### AND is generic utility functionality used by the ### daemon or test programs (all symbols in here should ### be underscore-prefixed) DBUS_SHARED_SOURCES = \ dbus-dataslot.c \ dbus-dataslot.h \ dbus-file.c \ dbus-file.h \ dbus-hash.c \ dbus-hash.h \ dbus-internals.c \ dbus-internals.h \ dbus-list.c \ dbus-list.h \ dbus-marshal-basic.c \ dbus-marshal-basic.h \ dbus-memory.c \ dbus-mempool.c \ dbus-mempool.h \ dbus-pipe.c \ dbus-pipe.h \ dbus-string.c \ dbus-string.h \ dbus-string-private.h \ $(DBUS_SHARED_arch_sources) \ dbus-sysdeps.c \ dbus-sysdeps.h \ dbus-valgrind-internal.h ### source code that is generic utility functionality used ### by the bus daemon or test apps, but is NOT included ### in the D-Bus client library (all symbols in here ### should be underscore-prefixed but don't really need ### to be unless they move to DBUS_SHARED_SOURCES later) DBUS_UTIL_SOURCES = \ dbus-asv-util.c \ dbus-asv-util.h \ dbus-auth-script.c \ dbus-auth-script.h \ dbus-auth-util.c \ dbus-credentials-util.c \ dbus-mainloop.c \ dbus-mainloop.h \ dbus-marshal-byteswap-util.c \ dbus-marshal-recursive-util.c \ dbus-marshal-validate-util.c \ dbus-message-factory.c \ dbus-message-factory.h \ dbus-message-util.c \ dbus-shell.c \ dbus-shell.h \ $(DBUS_UTIL_arch_sources) \ dbus-socket-set.h \ dbus-socket-set.c \ dbus-socket-set-poll.c \ dbus-spawn.h \ dbus-string-util.c \ dbus-sysdeps-util.c \ dbus-test.c \ dbus-test.h libdbus_1_la_SOURCES = \ $(DBUS_LIB_SOURCES) \ $(DBUS_SHARED_SOURCES) libdbus_internal_la_SOURCES = \ $(DBUS_UTIL_SOURCES) BUILT_SOURCES = $(nodist_dbusarchinclude_HEADERS) EXTRA_DIST = dbus-arch-deps.h.in noinst_LTLIBRARIES = libdbus-internal.la $(am__append_4) libdbus_1_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -Ddbus_1_EXPORTS \ $(NULL) @HAVE_LD_VERSION_SCRIPT_FALSE@SYMBOL_EXPORT_LDFLAGS = @HAVE_LD_VERSION_SCRIPT_TRUE@SYMBOL_EXPORT_LDFLAGS = -Wl,--version-script=Version libdbus_1_la_LIBADD = $(LIBDBUS_LIBS) $(am__append_5) libdbus_1_la_LDFLAGS = \ $(AM_LDFLAGS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ $(SYMBOL_EXPORT_LDFLAGS) \ -no-undefined \ $(NULL) libdbus_internal_la_LIBADD = $(LIBDBUS_LIBS) libdbus-1.la @DBUS_WIN_TRUE@libdbus_init_win_la_SOURCES = dbus-init-win.cpp test_dbus_SOURCES = \ dbus-test-main.c test_dbus_LDADD = libdbus-internal.la all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: rc .c .cpp .lo .o .obj .rc $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu dbus/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu dbus/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): Version: $(top_builddir)/config.status $(srcdir)/Version.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ versioninfo.rc: $(top_builddir)/config.status $(srcdir)/versioninfo.rc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dbus-arch-deps.h: $(top_builddir)/config.status $(srcdir)/dbus-arch-deps.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libdbus-1.la: $(libdbus_1_la_OBJECTS) $(libdbus_1_la_DEPENDENCIES) $(EXTRA_libdbus_1_la_DEPENDENCIES) $(AM_V_CCLD)$(libdbus_1_la_LINK) -rpath $(libdir) $(libdbus_1_la_OBJECTS) $(libdbus_1_la_LIBADD) $(LIBS) libdbus-init-win.la: $(libdbus_init_win_la_OBJECTS) $(libdbus_init_win_la_DEPENDENCIES) $(EXTRA_libdbus_init_win_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(am_libdbus_init_win_la_rpath) $(libdbus_init_win_la_OBJECTS) $(libdbus_init_win_la_LIBADD) $(LIBS) libdbus-internal.la: $(libdbus_internal_la_OBJECTS) $(libdbus_internal_la_DEPENDENCIES) $(EXTRA_libdbus_internal_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libdbus_internal_la_OBJECTS) $(libdbus_internal_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test-dbus$(EXEEXT): $(test_dbus_OBJECTS) $(test_dbus_DEPENDENCIES) $(EXTRA_test_dbus_DEPENDENCIES) @rm -f test-dbus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dbus_OBJECTS) $(test_dbus_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-asv-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-auth-script.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-auth-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-credentials-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-init-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-mainloop.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-byteswap-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-recursive-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-validate-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-message-factory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-message-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-shell.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-socket-set-epoll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-socket-set-poll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-socket-set.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-spawn-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-spawn.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-string-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-util-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-util-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-test-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-userdb-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-address.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-auth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-bus.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-credentials.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-dataslot.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-errors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-file-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-file-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-file.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-internals.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-keyring.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-list.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-marshal-basic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-marshal-byteswap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-marshal-header.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-marshal-recursive.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-marshal-validate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-memory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-mempool.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-nonce.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-object-tree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-pending-call.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-pipe-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-pipe-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-pipe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-resources.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server-debug-pipe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server-launchd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server-socket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sha.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-signature.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-syntax.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps-pthread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps-thread-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps-wince-glue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-sysdeps.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-timeout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-transport-socket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-transport-unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-transport-win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-transport.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-userdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-uuidgen.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_1_la-dbus-watch.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libdbus_1_la-dbus-address.lo: dbus-address.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-address.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-address.Tpo -c -o libdbus_1_la-dbus-address.lo `test -f 'dbus-address.c' || echo '$(srcdir)/'`dbus-address.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-address.Tpo $(DEPDIR)/libdbus_1_la-dbus-address.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-address.c' object='libdbus_1_la-dbus-address.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-address.lo `test -f 'dbus-address.c' || echo '$(srcdir)/'`dbus-address.c libdbus_1_la-dbus-auth.lo: dbus-auth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-auth.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-auth.Tpo -c -o libdbus_1_la-dbus-auth.lo `test -f 'dbus-auth.c' || echo '$(srcdir)/'`dbus-auth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-auth.Tpo $(DEPDIR)/libdbus_1_la-dbus-auth.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-auth.c' object='libdbus_1_la-dbus-auth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-auth.lo `test -f 'dbus-auth.c' || echo '$(srcdir)/'`dbus-auth.c libdbus_1_la-dbus-bus.lo: dbus-bus.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-bus.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-bus.Tpo -c -o libdbus_1_la-dbus-bus.lo `test -f 'dbus-bus.c' || echo '$(srcdir)/'`dbus-bus.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-bus.Tpo $(DEPDIR)/libdbus_1_la-dbus-bus.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-bus.c' object='libdbus_1_la-dbus-bus.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-bus.lo `test -f 'dbus-bus.c' || echo '$(srcdir)/'`dbus-bus.c libdbus_1_la-dbus-connection.lo: dbus-connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-connection.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-connection.Tpo -c -o libdbus_1_la-dbus-connection.lo `test -f 'dbus-connection.c' || echo '$(srcdir)/'`dbus-connection.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-connection.Tpo $(DEPDIR)/libdbus_1_la-dbus-connection.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-connection.c' object='libdbus_1_la-dbus-connection.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-connection.lo `test -f 'dbus-connection.c' || echo '$(srcdir)/'`dbus-connection.c libdbus_1_la-dbus-credentials.lo: dbus-credentials.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-credentials.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-credentials.Tpo -c -o libdbus_1_la-dbus-credentials.lo `test -f 'dbus-credentials.c' || echo '$(srcdir)/'`dbus-credentials.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-credentials.Tpo $(DEPDIR)/libdbus_1_la-dbus-credentials.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-credentials.c' object='libdbus_1_la-dbus-credentials.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-credentials.lo `test -f 'dbus-credentials.c' || echo '$(srcdir)/'`dbus-credentials.c libdbus_1_la-dbus-errors.lo: dbus-errors.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-errors.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-errors.Tpo -c -o libdbus_1_la-dbus-errors.lo `test -f 'dbus-errors.c' || echo '$(srcdir)/'`dbus-errors.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-errors.Tpo $(DEPDIR)/libdbus_1_la-dbus-errors.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-errors.c' object='libdbus_1_la-dbus-errors.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-errors.lo `test -f 'dbus-errors.c' || echo '$(srcdir)/'`dbus-errors.c libdbus_1_la-dbus-keyring.lo: dbus-keyring.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-keyring.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-keyring.Tpo -c -o libdbus_1_la-dbus-keyring.lo `test -f 'dbus-keyring.c' || echo '$(srcdir)/'`dbus-keyring.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-keyring.Tpo $(DEPDIR)/libdbus_1_la-dbus-keyring.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-keyring.c' object='libdbus_1_la-dbus-keyring.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-keyring.lo `test -f 'dbus-keyring.c' || echo '$(srcdir)/'`dbus-keyring.c libdbus_1_la-dbus-marshal-header.lo: dbus-marshal-header.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-marshal-header.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-marshal-header.Tpo -c -o libdbus_1_la-dbus-marshal-header.lo `test -f 'dbus-marshal-header.c' || echo '$(srcdir)/'`dbus-marshal-header.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-marshal-header.Tpo $(DEPDIR)/libdbus_1_la-dbus-marshal-header.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-marshal-header.c' object='libdbus_1_la-dbus-marshal-header.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-marshal-header.lo `test -f 'dbus-marshal-header.c' || echo '$(srcdir)/'`dbus-marshal-header.c libdbus_1_la-dbus-marshal-byteswap.lo: dbus-marshal-byteswap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-marshal-byteswap.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-marshal-byteswap.Tpo -c -o libdbus_1_la-dbus-marshal-byteswap.lo `test -f 'dbus-marshal-byteswap.c' || echo '$(srcdir)/'`dbus-marshal-byteswap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-marshal-byteswap.Tpo $(DEPDIR)/libdbus_1_la-dbus-marshal-byteswap.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-marshal-byteswap.c' object='libdbus_1_la-dbus-marshal-byteswap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-marshal-byteswap.lo `test -f 'dbus-marshal-byteswap.c' || echo '$(srcdir)/'`dbus-marshal-byteswap.c libdbus_1_la-dbus-marshal-recursive.lo: dbus-marshal-recursive.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-marshal-recursive.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-marshal-recursive.Tpo -c -o libdbus_1_la-dbus-marshal-recursive.lo `test -f 'dbus-marshal-recursive.c' || echo '$(srcdir)/'`dbus-marshal-recursive.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-marshal-recursive.Tpo $(DEPDIR)/libdbus_1_la-dbus-marshal-recursive.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-marshal-recursive.c' object='libdbus_1_la-dbus-marshal-recursive.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-marshal-recursive.lo `test -f 'dbus-marshal-recursive.c' || echo '$(srcdir)/'`dbus-marshal-recursive.c libdbus_1_la-dbus-marshal-validate.lo: dbus-marshal-validate.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-marshal-validate.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-marshal-validate.Tpo -c -o libdbus_1_la-dbus-marshal-validate.lo `test -f 'dbus-marshal-validate.c' || echo '$(srcdir)/'`dbus-marshal-validate.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-marshal-validate.Tpo $(DEPDIR)/libdbus_1_la-dbus-marshal-validate.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-marshal-validate.c' object='libdbus_1_la-dbus-marshal-validate.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-marshal-validate.lo `test -f 'dbus-marshal-validate.c' || echo '$(srcdir)/'`dbus-marshal-validate.c libdbus_1_la-dbus-message.lo: dbus-message.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-message.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-message.Tpo -c -o libdbus_1_la-dbus-message.lo `test -f 'dbus-message.c' || echo '$(srcdir)/'`dbus-message.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-message.Tpo $(DEPDIR)/libdbus_1_la-dbus-message.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-message.c' object='libdbus_1_la-dbus-message.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-message.lo `test -f 'dbus-message.c' || echo '$(srcdir)/'`dbus-message.c libdbus_1_la-dbus-misc.lo: dbus-misc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-misc.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-misc.Tpo -c -o libdbus_1_la-dbus-misc.lo `test -f 'dbus-misc.c' || echo '$(srcdir)/'`dbus-misc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-misc.Tpo $(DEPDIR)/libdbus_1_la-dbus-misc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-misc.c' object='libdbus_1_la-dbus-misc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-misc.lo `test -f 'dbus-misc.c' || echo '$(srcdir)/'`dbus-misc.c libdbus_1_la-dbus-nonce.lo: dbus-nonce.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-nonce.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-nonce.Tpo -c -o libdbus_1_la-dbus-nonce.lo `test -f 'dbus-nonce.c' || echo '$(srcdir)/'`dbus-nonce.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-nonce.Tpo $(DEPDIR)/libdbus_1_la-dbus-nonce.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-nonce.c' object='libdbus_1_la-dbus-nonce.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-nonce.lo `test -f 'dbus-nonce.c' || echo '$(srcdir)/'`dbus-nonce.c libdbus_1_la-dbus-object-tree.lo: dbus-object-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-object-tree.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-object-tree.Tpo -c -o libdbus_1_la-dbus-object-tree.lo `test -f 'dbus-object-tree.c' || echo '$(srcdir)/'`dbus-object-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-object-tree.Tpo $(DEPDIR)/libdbus_1_la-dbus-object-tree.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-object-tree.c' object='libdbus_1_la-dbus-object-tree.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-object-tree.lo `test -f 'dbus-object-tree.c' || echo '$(srcdir)/'`dbus-object-tree.c libdbus_1_la-dbus-pending-call.lo: dbus-pending-call.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-pending-call.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-pending-call.Tpo -c -o libdbus_1_la-dbus-pending-call.lo `test -f 'dbus-pending-call.c' || echo '$(srcdir)/'`dbus-pending-call.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-pending-call.Tpo $(DEPDIR)/libdbus_1_la-dbus-pending-call.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-pending-call.c' object='libdbus_1_la-dbus-pending-call.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-pending-call.lo `test -f 'dbus-pending-call.c' || echo '$(srcdir)/'`dbus-pending-call.c libdbus_1_la-dbus-resources.lo: dbus-resources.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-resources.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-resources.Tpo -c -o libdbus_1_la-dbus-resources.lo `test -f 'dbus-resources.c' || echo '$(srcdir)/'`dbus-resources.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-resources.Tpo $(DEPDIR)/libdbus_1_la-dbus-resources.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-resources.c' object='libdbus_1_la-dbus-resources.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-resources.lo `test -f 'dbus-resources.c' || echo '$(srcdir)/'`dbus-resources.c libdbus_1_la-dbus-server.lo: dbus-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server.Tpo -c -o libdbus_1_la-dbus-server.lo `test -f 'dbus-server.c' || echo '$(srcdir)/'`dbus-server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server.Tpo $(DEPDIR)/libdbus_1_la-dbus-server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server.c' object='libdbus_1_la-dbus-server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server.lo `test -f 'dbus-server.c' || echo '$(srcdir)/'`dbus-server.c libdbus_1_la-dbus-server-debug-pipe.lo: dbus-server-debug-pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server-debug-pipe.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server-debug-pipe.Tpo -c -o libdbus_1_la-dbus-server-debug-pipe.lo `test -f 'dbus-server-debug-pipe.c' || echo '$(srcdir)/'`dbus-server-debug-pipe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server-debug-pipe.Tpo $(DEPDIR)/libdbus_1_la-dbus-server-debug-pipe.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server-debug-pipe.c' object='libdbus_1_la-dbus-server-debug-pipe.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server-debug-pipe.lo `test -f 'dbus-server-debug-pipe.c' || echo '$(srcdir)/'`dbus-server-debug-pipe.c libdbus_1_la-dbus-server-socket.lo: dbus-server-socket.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server-socket.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server-socket.Tpo -c -o libdbus_1_la-dbus-server-socket.lo `test -f 'dbus-server-socket.c' || echo '$(srcdir)/'`dbus-server-socket.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server-socket.Tpo $(DEPDIR)/libdbus_1_la-dbus-server-socket.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server-socket.c' object='libdbus_1_la-dbus-server-socket.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server-socket.lo `test -f 'dbus-server-socket.c' || echo '$(srcdir)/'`dbus-server-socket.c libdbus_1_la-dbus-uuidgen.lo: dbus-uuidgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-uuidgen.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-uuidgen.Tpo -c -o libdbus_1_la-dbus-uuidgen.lo `test -f 'dbus-uuidgen.c' || echo '$(srcdir)/'`dbus-uuidgen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-uuidgen.Tpo $(DEPDIR)/libdbus_1_la-dbus-uuidgen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-uuidgen.c' object='libdbus_1_la-dbus-uuidgen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-uuidgen.lo `test -f 'dbus-uuidgen.c' || echo '$(srcdir)/'`dbus-uuidgen.c libdbus_1_la-dbus-server-unix.lo: dbus-server-unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server-unix.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server-unix.Tpo -c -o libdbus_1_la-dbus-server-unix.lo `test -f 'dbus-server-unix.c' || echo '$(srcdir)/'`dbus-server-unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server-unix.Tpo $(DEPDIR)/libdbus_1_la-dbus-server-unix.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server-unix.c' object='libdbus_1_la-dbus-server-unix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server-unix.lo `test -f 'dbus-server-unix.c' || echo '$(srcdir)/'`dbus-server-unix.c libdbus_1_la-dbus-server-win.lo: dbus-server-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server-win.Tpo -c -o libdbus_1_la-dbus-server-win.lo `test -f 'dbus-server-win.c' || echo '$(srcdir)/'`dbus-server-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-server-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server-win.c' object='libdbus_1_la-dbus-server-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server-win.lo `test -f 'dbus-server-win.c' || echo '$(srcdir)/'`dbus-server-win.c libdbus_1_la-dbus-sha.lo: dbus-sha.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sha.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sha.Tpo -c -o libdbus_1_la-dbus-sha.lo `test -f 'dbus-sha.c' || echo '$(srcdir)/'`dbus-sha.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sha.Tpo $(DEPDIR)/libdbus_1_la-dbus-sha.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sha.c' object='libdbus_1_la-dbus-sha.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sha.lo `test -f 'dbus-sha.c' || echo '$(srcdir)/'`dbus-sha.c libdbus_1_la-dbus-signature.lo: dbus-signature.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-signature.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-signature.Tpo -c -o libdbus_1_la-dbus-signature.lo `test -f 'dbus-signature.c' || echo '$(srcdir)/'`dbus-signature.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-signature.Tpo $(DEPDIR)/libdbus_1_la-dbus-signature.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-signature.c' object='libdbus_1_la-dbus-signature.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-signature.lo `test -f 'dbus-signature.c' || echo '$(srcdir)/'`dbus-signature.c libdbus_1_la-dbus-syntax.lo: dbus-syntax.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-syntax.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-syntax.Tpo -c -o libdbus_1_la-dbus-syntax.lo `test -f 'dbus-syntax.c' || echo '$(srcdir)/'`dbus-syntax.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-syntax.Tpo $(DEPDIR)/libdbus_1_la-dbus-syntax.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-syntax.c' object='libdbus_1_la-dbus-syntax.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-syntax.lo `test -f 'dbus-syntax.c' || echo '$(srcdir)/'`dbus-syntax.c libdbus_1_la-dbus-timeout.lo: dbus-timeout.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-timeout.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-timeout.Tpo -c -o libdbus_1_la-dbus-timeout.lo `test -f 'dbus-timeout.c' || echo '$(srcdir)/'`dbus-timeout.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-timeout.Tpo $(DEPDIR)/libdbus_1_la-dbus-timeout.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-timeout.c' object='libdbus_1_la-dbus-timeout.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-timeout.lo `test -f 'dbus-timeout.c' || echo '$(srcdir)/'`dbus-timeout.c libdbus_1_la-dbus-threads.lo: dbus-threads.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-threads.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-threads.Tpo -c -o libdbus_1_la-dbus-threads.lo `test -f 'dbus-threads.c' || echo '$(srcdir)/'`dbus-threads.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-threads.Tpo $(DEPDIR)/libdbus_1_la-dbus-threads.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-threads.c' object='libdbus_1_la-dbus-threads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-threads.lo `test -f 'dbus-threads.c' || echo '$(srcdir)/'`dbus-threads.c libdbus_1_la-dbus-transport.lo: dbus-transport.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-transport.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-transport.Tpo -c -o libdbus_1_la-dbus-transport.lo `test -f 'dbus-transport.c' || echo '$(srcdir)/'`dbus-transport.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-transport.Tpo $(DEPDIR)/libdbus_1_la-dbus-transport.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-transport.c' object='libdbus_1_la-dbus-transport.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-transport.lo `test -f 'dbus-transport.c' || echo '$(srcdir)/'`dbus-transport.c libdbus_1_la-dbus-transport-socket.lo: dbus-transport-socket.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-transport-socket.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-transport-socket.Tpo -c -o libdbus_1_la-dbus-transport-socket.lo `test -f 'dbus-transport-socket.c' || echo '$(srcdir)/'`dbus-transport-socket.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-transport-socket.Tpo $(DEPDIR)/libdbus_1_la-dbus-transport-socket.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-transport-socket.c' object='libdbus_1_la-dbus-transport-socket.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-transport-socket.lo `test -f 'dbus-transport-socket.c' || echo '$(srcdir)/'`dbus-transport-socket.c libdbus_1_la-dbus-watch.lo: dbus-watch.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-watch.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-watch.Tpo -c -o libdbus_1_la-dbus-watch.lo `test -f 'dbus-watch.c' || echo '$(srcdir)/'`dbus-watch.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-watch.Tpo $(DEPDIR)/libdbus_1_la-dbus-watch.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-watch.c' object='libdbus_1_la-dbus-watch.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-watch.lo `test -f 'dbus-watch.c' || echo '$(srcdir)/'`dbus-watch.c libdbus_1_la-dbus-dataslot.lo: dbus-dataslot.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-dataslot.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-dataslot.Tpo -c -o libdbus_1_la-dbus-dataslot.lo `test -f 'dbus-dataslot.c' || echo '$(srcdir)/'`dbus-dataslot.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-dataslot.Tpo $(DEPDIR)/libdbus_1_la-dbus-dataslot.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-dataslot.c' object='libdbus_1_la-dbus-dataslot.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-dataslot.lo `test -f 'dbus-dataslot.c' || echo '$(srcdir)/'`dbus-dataslot.c libdbus_1_la-dbus-file.lo: dbus-file.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-file.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-file.Tpo -c -o libdbus_1_la-dbus-file.lo `test -f 'dbus-file.c' || echo '$(srcdir)/'`dbus-file.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-file.Tpo $(DEPDIR)/libdbus_1_la-dbus-file.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-file.c' object='libdbus_1_la-dbus-file.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-file.lo `test -f 'dbus-file.c' || echo '$(srcdir)/'`dbus-file.c libdbus_1_la-dbus-hash.lo: dbus-hash.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-hash.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-hash.Tpo -c -o libdbus_1_la-dbus-hash.lo `test -f 'dbus-hash.c' || echo '$(srcdir)/'`dbus-hash.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-hash.Tpo $(DEPDIR)/libdbus_1_la-dbus-hash.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-hash.c' object='libdbus_1_la-dbus-hash.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-hash.lo `test -f 'dbus-hash.c' || echo '$(srcdir)/'`dbus-hash.c libdbus_1_la-dbus-internals.lo: dbus-internals.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-internals.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-internals.Tpo -c -o libdbus_1_la-dbus-internals.lo `test -f 'dbus-internals.c' || echo '$(srcdir)/'`dbus-internals.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-internals.Tpo $(DEPDIR)/libdbus_1_la-dbus-internals.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-internals.c' object='libdbus_1_la-dbus-internals.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-internals.lo `test -f 'dbus-internals.c' || echo '$(srcdir)/'`dbus-internals.c libdbus_1_la-dbus-list.lo: dbus-list.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-list.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-list.Tpo -c -o libdbus_1_la-dbus-list.lo `test -f 'dbus-list.c' || echo '$(srcdir)/'`dbus-list.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-list.Tpo $(DEPDIR)/libdbus_1_la-dbus-list.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-list.c' object='libdbus_1_la-dbus-list.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-list.lo `test -f 'dbus-list.c' || echo '$(srcdir)/'`dbus-list.c libdbus_1_la-dbus-marshal-basic.lo: dbus-marshal-basic.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-marshal-basic.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-marshal-basic.Tpo -c -o libdbus_1_la-dbus-marshal-basic.lo `test -f 'dbus-marshal-basic.c' || echo '$(srcdir)/'`dbus-marshal-basic.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-marshal-basic.Tpo $(DEPDIR)/libdbus_1_la-dbus-marshal-basic.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-marshal-basic.c' object='libdbus_1_la-dbus-marshal-basic.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-marshal-basic.lo `test -f 'dbus-marshal-basic.c' || echo '$(srcdir)/'`dbus-marshal-basic.c libdbus_1_la-dbus-memory.lo: dbus-memory.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-memory.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-memory.Tpo -c -o libdbus_1_la-dbus-memory.lo `test -f 'dbus-memory.c' || echo '$(srcdir)/'`dbus-memory.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-memory.Tpo $(DEPDIR)/libdbus_1_la-dbus-memory.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-memory.c' object='libdbus_1_la-dbus-memory.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-memory.lo `test -f 'dbus-memory.c' || echo '$(srcdir)/'`dbus-memory.c libdbus_1_la-dbus-mempool.lo: dbus-mempool.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-mempool.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-mempool.Tpo -c -o libdbus_1_la-dbus-mempool.lo `test -f 'dbus-mempool.c' || echo '$(srcdir)/'`dbus-mempool.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-mempool.Tpo $(DEPDIR)/libdbus_1_la-dbus-mempool.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-mempool.c' object='libdbus_1_la-dbus-mempool.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-mempool.lo `test -f 'dbus-mempool.c' || echo '$(srcdir)/'`dbus-mempool.c libdbus_1_la-dbus-pipe.lo: dbus-pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-pipe.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-pipe.Tpo -c -o libdbus_1_la-dbus-pipe.lo `test -f 'dbus-pipe.c' || echo '$(srcdir)/'`dbus-pipe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-pipe.Tpo $(DEPDIR)/libdbus_1_la-dbus-pipe.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-pipe.c' object='libdbus_1_la-dbus-pipe.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-pipe.lo `test -f 'dbus-pipe.c' || echo '$(srcdir)/'`dbus-pipe.c libdbus_1_la-dbus-string.lo: dbus-string.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-string.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-string.Tpo -c -o libdbus_1_la-dbus-string.lo `test -f 'dbus-string.c' || echo '$(srcdir)/'`dbus-string.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-string.Tpo $(DEPDIR)/libdbus_1_la-dbus-string.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-string.c' object='libdbus_1_la-dbus-string.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-string.lo `test -f 'dbus-string.c' || echo '$(srcdir)/'`dbus-string.c libdbus_1_la-dbus-server-launchd.lo: dbus-server-launchd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-server-launchd.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-server-launchd.Tpo -c -o libdbus_1_la-dbus-server-launchd.lo `test -f 'dbus-server-launchd.c' || echo '$(srcdir)/'`dbus-server-launchd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-server-launchd.Tpo $(DEPDIR)/libdbus_1_la-dbus-server-launchd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-server-launchd.c' object='libdbus_1_la-dbus-server-launchd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-server-launchd.lo `test -f 'dbus-server-launchd.c' || echo '$(srcdir)/'`dbus-server-launchd.c libdbus_1_la-dbus-file-unix.lo: dbus-file-unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-file-unix.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-file-unix.Tpo -c -o libdbus_1_la-dbus-file-unix.lo `test -f 'dbus-file-unix.c' || echo '$(srcdir)/'`dbus-file-unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-file-unix.Tpo $(DEPDIR)/libdbus_1_la-dbus-file-unix.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-file-unix.c' object='libdbus_1_la-dbus-file-unix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-file-unix.lo `test -f 'dbus-file-unix.c' || echo '$(srcdir)/'`dbus-file-unix.c libdbus_1_la-dbus-pipe-unix.lo: dbus-pipe-unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-pipe-unix.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-pipe-unix.Tpo -c -o libdbus_1_la-dbus-pipe-unix.lo `test -f 'dbus-pipe-unix.c' || echo '$(srcdir)/'`dbus-pipe-unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-pipe-unix.Tpo $(DEPDIR)/libdbus_1_la-dbus-pipe-unix.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-pipe-unix.c' object='libdbus_1_la-dbus-pipe-unix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-pipe-unix.lo `test -f 'dbus-pipe-unix.c' || echo '$(srcdir)/'`dbus-pipe-unix.c libdbus_1_la-dbus-sysdeps-unix.lo: dbus-sysdeps-unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps-unix.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps-unix.Tpo -c -o libdbus_1_la-dbus-sysdeps-unix.lo `test -f 'dbus-sysdeps-unix.c' || echo '$(srcdir)/'`dbus-sysdeps-unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps-unix.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps-unix.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps-unix.c' object='libdbus_1_la-dbus-sysdeps-unix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps-unix.lo `test -f 'dbus-sysdeps-unix.c' || echo '$(srcdir)/'`dbus-sysdeps-unix.c libdbus_1_la-dbus-sysdeps-pthread.lo: dbus-sysdeps-pthread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps-pthread.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps-pthread.Tpo -c -o libdbus_1_la-dbus-sysdeps-pthread.lo `test -f 'dbus-sysdeps-pthread.c' || echo '$(srcdir)/'`dbus-sysdeps-pthread.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps-pthread.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps-pthread.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps-pthread.c' object='libdbus_1_la-dbus-sysdeps-pthread.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps-pthread.lo `test -f 'dbus-sysdeps-pthread.c' || echo '$(srcdir)/'`dbus-sysdeps-pthread.c libdbus_1_la-dbus-transport-unix.lo: dbus-transport-unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-transport-unix.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-transport-unix.Tpo -c -o libdbus_1_la-dbus-transport-unix.lo `test -f 'dbus-transport-unix.c' || echo '$(srcdir)/'`dbus-transport-unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-transport-unix.Tpo $(DEPDIR)/libdbus_1_la-dbus-transport-unix.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-transport-unix.c' object='libdbus_1_la-dbus-transport-unix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-transport-unix.lo `test -f 'dbus-transport-unix.c' || echo '$(srcdir)/'`dbus-transport-unix.c libdbus_1_la-dbus-userdb.lo: dbus-userdb.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-userdb.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-userdb.Tpo -c -o libdbus_1_la-dbus-userdb.lo `test -f 'dbus-userdb.c' || echo '$(srcdir)/'`dbus-userdb.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-userdb.Tpo $(DEPDIR)/libdbus_1_la-dbus-userdb.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-userdb.c' object='libdbus_1_la-dbus-userdb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-userdb.lo `test -f 'dbus-userdb.c' || echo '$(srcdir)/'`dbus-userdb.c libdbus_1_la-dbus-sysdeps-wince-glue.lo: dbus-sysdeps-wince-glue.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps-wince-glue.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps-wince-glue.Tpo -c -o libdbus_1_la-dbus-sysdeps-wince-glue.lo `test -f 'dbus-sysdeps-wince-glue.c' || echo '$(srcdir)/'`dbus-sysdeps-wince-glue.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps-wince-glue.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps-wince-glue.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps-wince-glue.c' object='libdbus_1_la-dbus-sysdeps-wince-glue.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps-wince-glue.lo `test -f 'dbus-sysdeps-wince-glue.c' || echo '$(srcdir)/'`dbus-sysdeps-wince-glue.c libdbus_1_la-dbus-file-win.lo: dbus-file-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-file-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-file-win.Tpo -c -o libdbus_1_la-dbus-file-win.lo `test -f 'dbus-file-win.c' || echo '$(srcdir)/'`dbus-file-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-file-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-file-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-file-win.c' object='libdbus_1_la-dbus-file-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-file-win.lo `test -f 'dbus-file-win.c' || echo '$(srcdir)/'`dbus-file-win.c libdbus_1_la-dbus-pipe-win.lo: dbus-pipe-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-pipe-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-pipe-win.Tpo -c -o libdbus_1_la-dbus-pipe-win.lo `test -f 'dbus-pipe-win.c' || echo '$(srcdir)/'`dbus-pipe-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-pipe-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-pipe-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-pipe-win.c' object='libdbus_1_la-dbus-pipe-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-pipe-win.lo `test -f 'dbus-pipe-win.c' || echo '$(srcdir)/'`dbus-pipe-win.c libdbus_1_la-dbus-sysdeps-win.lo: dbus-sysdeps-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps-win.Tpo -c -o libdbus_1_la-dbus-sysdeps-win.lo `test -f 'dbus-sysdeps-win.c' || echo '$(srcdir)/'`dbus-sysdeps-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps-win.c' object='libdbus_1_la-dbus-sysdeps-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps-win.lo `test -f 'dbus-sysdeps-win.c' || echo '$(srcdir)/'`dbus-sysdeps-win.c libdbus_1_la-dbus-sysdeps-thread-win.lo: dbus-sysdeps-thread-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps-thread-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps-thread-win.Tpo -c -o libdbus_1_la-dbus-sysdeps-thread-win.lo `test -f 'dbus-sysdeps-thread-win.c' || echo '$(srcdir)/'`dbus-sysdeps-thread-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps-thread-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps-thread-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps-thread-win.c' object='libdbus_1_la-dbus-sysdeps-thread-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps-thread-win.lo `test -f 'dbus-sysdeps-thread-win.c' || echo '$(srcdir)/'`dbus-sysdeps-thread-win.c libdbus_1_la-dbus-transport-win.lo: dbus-transport-win.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-transport-win.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-transport-win.Tpo -c -o libdbus_1_la-dbus-transport-win.lo `test -f 'dbus-transport-win.c' || echo '$(srcdir)/'`dbus-transport-win.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-transport-win.Tpo $(DEPDIR)/libdbus_1_la-dbus-transport-win.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-transport-win.c' object='libdbus_1_la-dbus-transport-win.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-transport-win.lo `test -f 'dbus-transport-win.c' || echo '$(srcdir)/'`dbus-transport-win.c libdbus_1_la-dbus-sysdeps.lo: dbus-sysdeps.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdbus_1_la-dbus-sysdeps.lo -MD -MP -MF $(DEPDIR)/libdbus_1_la-dbus-sysdeps.Tpo -c -o libdbus_1_la-dbus-sysdeps.lo `test -f 'dbus-sysdeps.c' || echo '$(srcdir)/'`dbus-sysdeps.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdbus_1_la-dbus-sysdeps.Tpo $(DEPDIR)/libdbus_1_la-dbus-sysdeps.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dbus-sysdeps.c' object='libdbus_1_la-dbus-sysdeps.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdbus_1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdbus_1_la-dbus-sysdeps.lo `test -f 'dbus-sysdeps.c' || echo '$(srcdir)/'`dbus-sysdeps.c .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dbusincludeHEADERS: $(dbusinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(dbusinclude_HEADERS)'; test -n "$(dbusincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dbusincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dbusincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(dbusincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(dbusincludedir)" || exit $$?; \ done uninstall-dbusincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(dbusinclude_HEADERS)'; test -n "$(dbusincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(dbusincludedir)'; $(am__uninstall_files_from_dir) install-nodist_dbusarchincludeHEADERS: $(nodist_dbusarchinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(nodist_dbusarchinclude_HEADERS)'; test -n "$(dbusarchincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dbusarchincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dbusarchincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(dbusarchincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(dbusarchincludedir)" || exit $$?; \ done uninstall-nodist_dbusarchincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_dbusarchinclude_HEADERS)'; test -n "$(dbusarchincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(dbusarchincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(dbusincludedir)" "$(DESTDIR)$(dbusarchincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dbusincludeHEADERS \ install-nodist_dbusarchincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dbusincludeHEADERS uninstall-libLTLIBRARIES \ uninstall-nodist_dbusarchincludeHEADERS .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dbusincludeHEADERS install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man \ install-nodist_dbusarchincludeHEADERS install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dbusincludeHEADERS uninstall-libLTLIBRARIES \ uninstall-nodist_dbusarchincludeHEADERS .PRECIOUS: Makefile @DBUS_WIN_TRUE@.rc.o: @DBUS_WIN_TRUE@ $(WINDRES) $< -o $@ clean-local: /bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dbus-1.10.6/dbus/dbus-types.h0000644000175000017500000001006112602773110015740 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-types.h types such as dbus_bool_t * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_TYPES_H #define DBUS_TYPES_H #include #include typedef dbus_uint32_t dbus_unichar_t; /* boolean size must be fixed at 4 bytes due to wire protocol! */ typedef dbus_uint32_t dbus_bool_t; /* Normally docs are in .c files, but there isn't a .c file for this. */ /** * @defgroup DBusTypes Basic types * @ingroup DBus * @brief dbus_bool_t, dbus_int32_t, etc. * * Typedefs for common primitive types. * * @{ */ /** * @typedef dbus_bool_t * * A boolean, valid values are #TRUE and #FALSE. */ /** * @typedef dbus_uint32_t * * A 32-bit unsigned integer on all platforms. */ /** * @typedef dbus_int32_t * * A 32-bit signed integer on all platforms. */ /** * @typedef dbus_uint16_t * * A 16-bit unsigned integer on all platforms. */ /** * @typedef dbus_int16_t * * A 16-bit signed integer on all platforms. */ /** * @typedef dbus_uint64_t * * A 64-bit unsigned integer. */ /** * @typedef dbus_int64_t * * A 64-bit signed integer. */ /** * @def DBUS_HAVE_INT64 * * Always defined. * * In older libdbus versions, this would be undefined if there was no * 64-bit integer type on that platform. libdbus no longer supports * such platforms. */ /** * @def DBUS_INT64_CONSTANT * * Declare a 64-bit signed integer constant. The macro * adds the necessary "LL" or whatever after the integer, * giving a literal such as "325145246765LL" */ /** * @def DBUS_UINT64_CONSTANT * * Declare a 64-bit unsigned integer constant. The macro * adds the necessary "ULL" or whatever after the integer, * giving a literal such as "325145246765ULL" */ /** * An 8-byte struct you could use to access int64 without having * int64 support. Use #dbus_int64_t or #dbus_uint64_t instead. */ typedef struct { dbus_uint32_t first32; /**< first 32 bits in the 8 bytes (beware endian issues) */ dbus_uint32_t second32; /**< second 32 bits in the 8 bytes (beware endian issues) */ } DBus8ByteStruct; /** * A simple value union that lets you access bytes as if they * were various types; useful when dealing with basic types via * void pointers and varargs. * * This union also contains a pointer member (which can be used * to retrieve a string from dbus_message_iter_get_basic(), for * instance), so on future platforms it could conceivably be larger * than 8 bytes. */ typedef union { unsigned char bytes[8]; /**< as 8 individual bytes */ dbus_int16_t i16; /**< as int16 */ dbus_uint16_t u16; /**< as int16 */ dbus_int32_t i32; /**< as int32 */ dbus_uint32_t u32; /**< as int32 */ dbus_bool_t bool_val; /**< as boolean */ dbus_int64_t i64; /**< as int64 */ dbus_uint64_t u64; /**< as int64 */ DBus8ByteStruct eight; /**< as 8-byte struct */ double dbl; /**< as double */ unsigned char byt; /**< as byte */ char *str; /**< as char* (string, object path or signature) */ int fd; /**< as Unix file descriptor */ } DBusBasicValue; /** @} */ #endif /* DBUS_TYPES_H */ dbus-1.10.6/dbus/dbus-threads.h0000644000175000017500000002047312602773110016236 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-threads.h D-Bus threads handling * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_THREADS_H #define DBUS_THREADS_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusThreads * @{ */ /** An opaque mutex type provided by the #DBusThreadFunctions implementation installed by dbus_threads_init(). */ typedef struct DBusMutex DBusMutex; /** An opaque condition variable type provided by the #DBusThreadFunctions implementation installed by dbus_threads_init(). */ typedef struct DBusCondVar DBusCondVar; /** Deprecated, provide DBusRecursiveMutexNewFunction instead. */ typedef DBusMutex* (* DBusMutexNewFunction) (void); /** Deprecated, provide DBusRecursiveMutexFreeFunction instead. */ typedef void (* DBusMutexFreeFunction) (DBusMutex *mutex); /** Deprecated, provide DBusRecursiveMutexLockFunction instead. Return value is lock success, but gets ignored in practice. */ typedef dbus_bool_t (* DBusMutexLockFunction) (DBusMutex *mutex); /** Deprecated, provide DBusRecursiveMutexUnlockFunction instead. Return value is unlock success, but gets ignored in practice. */ typedef dbus_bool_t (* DBusMutexUnlockFunction) (DBusMutex *mutex); /** Creates a new recursively-lockable mutex, or returns #NULL if not * enough memory. Can only fail due to lack of memory. Found in * #DBusThreadFunctions. Do not just use PTHREAD_MUTEX_RECURSIVE for * this, because it does not save/restore the recursion count when * waiting on a condition. libdbus requires the Java-style behavior * where the mutex is fully unlocked to wait on a condition. */ typedef DBusMutex* (* DBusRecursiveMutexNewFunction) (void); /** Frees a recursively-lockable mutex. Found in #DBusThreadFunctions. */ typedef void (* DBusRecursiveMutexFreeFunction) (DBusMutex *mutex); /** Locks a recursively-lockable mutex. Found in #DBusThreadFunctions. * Can only fail due to lack of memory. */ typedef void (* DBusRecursiveMutexLockFunction) (DBusMutex *mutex); /** Unlocks a recursively-lockable mutex. Found in #DBusThreadFunctions. * Can only fail due to lack of memory. */ typedef void (* DBusRecursiveMutexUnlockFunction) (DBusMutex *mutex); /** Creates a new condition variable. Found in #DBusThreadFunctions. * Can only fail (returning #NULL) due to lack of memory. */ typedef DBusCondVar* (* DBusCondVarNewFunction) (void); /** Frees a condition variable. Found in #DBusThreadFunctions. */ typedef void (* DBusCondVarFreeFunction) (DBusCondVar *cond); /** Waits on a condition variable. Found in * #DBusThreadFunctions. Must work with either a recursive or * nonrecursive mutex, whichever the thread implementation * provides. Note that PTHREAD_MUTEX_RECURSIVE does not work with * condition variables (does not save/restore the recursion count) so * don't try using simply pthread_cond_wait() and a * PTHREAD_MUTEX_RECURSIVE to implement this, it won't work right. * * Has no error conditions. Must succeed if it returns. */ typedef void (* DBusCondVarWaitFunction) (DBusCondVar *cond, DBusMutex *mutex); /** Waits on a condition variable with a timeout. Found in * #DBusThreadFunctions. Returns #TRUE if the wait did not * time out, and #FALSE if it did. * * Has no error conditions. Must succeed if it returns. */ typedef dbus_bool_t (* DBusCondVarWaitTimeoutFunction) (DBusCondVar *cond, DBusMutex *mutex, int timeout_milliseconds); /** Wakes one waiting thread on a condition variable. Found in #DBusThreadFunctions. * * Has no error conditions. Must succeed if it returns. */ typedef void (* DBusCondVarWakeOneFunction) (DBusCondVar *cond); /** Wakes all waiting threads on a condition variable. Found in #DBusThreadFunctions. * * Has no error conditions. Must succeed if it returns. */ typedef void (* DBusCondVarWakeAllFunction) (DBusCondVar *cond); /** * Flags indicating which functions are present in #DBusThreadFunctions. Used to allow * the library to detect older callers of dbus_threads_init() if new possible functions * are added to #DBusThreadFunctions. */ typedef enum { DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK = 1 << 0, DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK = 1 << 1, DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK = 1 << 2, DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK = 1 << 3, DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK = 1 << 4, DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK = 1 << 5, DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK = 1 << 6, DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK = 1 << 7, DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK = 1 << 8, DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK = 1 << 9, DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK = 1 << 10, DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK = 1 << 11, DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK = 1 << 12, DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK = 1 << 13, DBUS_THREAD_FUNCTIONS_ALL_MASK = (1 << 14) - 1 } DBusThreadFunctionsMask; /** * Functions that must be implemented to make the D-Bus library * thread-aware. * * If you supply both recursive and non-recursive mutexes, * libdbus will use the non-recursive version for condition variables, * and the recursive version in other contexts. * * The condition variable functions have to work with nonrecursive * mutexes if you provide those, or with recursive mutexes if you * don't. */ typedef struct { unsigned int mask; /**< Mask indicating which functions are present. */ DBusMutexNewFunction mutex_new; /**< Function to create a mutex; optional and deprecated. */ DBusMutexFreeFunction mutex_free; /**< Function to free a mutex; optional and deprecated. */ DBusMutexLockFunction mutex_lock; /**< Function to lock a mutex; optional and deprecated. */ DBusMutexUnlockFunction mutex_unlock; /**< Function to unlock a mutex; optional and deprecated. */ DBusCondVarNewFunction condvar_new; /**< Function to create a condition variable */ DBusCondVarFreeFunction condvar_free; /**< Function to free a condition variable */ DBusCondVarWaitFunction condvar_wait; /**< Function to wait on a condition */ DBusCondVarWaitTimeoutFunction condvar_wait_timeout; /**< Function to wait on a condition with a timeout */ DBusCondVarWakeOneFunction condvar_wake_one; /**< Function to wake one thread waiting on the condition */ DBusCondVarWakeAllFunction condvar_wake_all; /**< Function to wake all threads waiting on the condition */ DBusRecursiveMutexNewFunction recursive_mutex_new; /**< Function to create a recursive mutex */ DBusRecursiveMutexFreeFunction recursive_mutex_free; /**< Function to free a recursive mutex */ DBusRecursiveMutexLockFunction recursive_mutex_lock; /**< Function to lock a recursive mutex */ DBusRecursiveMutexUnlockFunction recursive_mutex_unlock; /**< Function to unlock a recursive mutex */ void (* padding1) (void); /**< Reserved for future expansion */ void (* padding2) (void); /**< Reserved for future expansion */ void (* padding3) (void); /**< Reserved for future expansion */ void (* padding4) (void); /**< Reserved for future expansion */ } DBusThreadFunctions; DBUS_EXPORT dbus_bool_t dbus_threads_init (const DBusThreadFunctions *functions); DBUS_EXPORT dbus_bool_t dbus_threads_init_default (void); /** @} */ DBUS_END_DECLS #endif /* DBUS_THREADS_H */ dbus-1.10.6/dbus/dbus-syntax.h0000644000175000017500000000446712602773110016137 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-syntax.h - utility functions for strings with special syntax * * Author: Simon McVittie * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_SYNTAX_H #define DBUS_SYNTAX_H #include #include #include DBUS_BEGIN_DECLS DBUS_EXPORT dbus_bool_t dbus_validate_path (const char *path, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_validate_interface (const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_validate_member (const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_validate_error_name (const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_validate_bus_name (const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_validate_utf8 (const char *alleged_utf8, DBusError *error); DBUS_END_DECLS #endif /* multiple-inclusion guard */ dbus-1.10.6/dbus/dbus-signature.h0000644000175000017500000000575112602773110016607 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-signatures.h utility functions for D-Bus types * * Copyright (C) 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_SIGNATURES_H #define DBUS_SIGNATURES_H #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusSignature * @{ */ /** * DBusSignatureIter struct; contains no public fields */ typedef struct { void *dummy1; /**< Don't use this */ void *dummy2; /**< Don't use this */ dbus_uint32_t dummy8; /**< Don't use this */ int dummy12; /**< Don't use this */ int dummy17; /**< Don't use this */ } DBusSignatureIter; DBUS_EXPORT void dbus_signature_iter_init (DBusSignatureIter *iter, const char *signature); DBUS_EXPORT int dbus_signature_iter_get_current_type (const DBusSignatureIter *iter); DBUS_EXPORT char * dbus_signature_iter_get_signature (const DBusSignatureIter *iter); DBUS_EXPORT int dbus_signature_iter_get_element_type (const DBusSignatureIter *iter); DBUS_EXPORT dbus_bool_t dbus_signature_iter_next (DBusSignatureIter *iter); DBUS_EXPORT void dbus_signature_iter_recurse (const DBusSignatureIter *iter, DBusSignatureIter *subiter); DBUS_EXPORT dbus_bool_t dbus_signature_validate (const char *signature, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_signature_validate_single (const char *signature, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_type_is_valid (int typecode); DBUS_EXPORT dbus_bool_t dbus_type_is_basic (int typecode); DBUS_EXPORT dbus_bool_t dbus_type_is_container (int typecode); DBUS_EXPORT dbus_bool_t dbus_type_is_fixed (int typecode); /** @} */ DBUS_END_DECLS #endif /* DBUS_SIGNATURE_H */ dbus-1.10.6/dbus/dbus-shared.h0000644000175000017500000001242212602773110016045 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-shared.h Stuff used by both dbus/dbus.h low-level and C/C++ binding APIs * * Copyright (C) 2004 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_SHARED_H #define DBUS_SHARED_H /* Don't include anything in here from anywhere else. It's * intended for use by any random library. */ #ifdef __cplusplus extern "C" { #if 0 } /* avoids confusing emacs indentation */ #endif #endif /* Normally docs are in .c files, but there isn't a .c file for this. */ /** * @defgroup DBusShared Shared constants * @ingroup DBus * * @brief Shared header included by both libdbus and C/C++ bindings such as the GLib bindings. * * Usually a C/C++ binding such as the GLib or Qt binding won't want to include dbus.h in its * public headers. However, a few constants and macros may be useful to include; those are * found here and in dbus-protocol.h * * @{ */ /** * Well-known bus types. See dbus_bus_get(). */ typedef enum { DBUS_BUS_SESSION, /**< The login session bus */ DBUS_BUS_SYSTEM, /**< The systemwide bus */ DBUS_BUS_STARTER /**< The bus that started us, if any */ } DBusBusType; /** * Results that a message handler can return. */ typedef enum { DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect - no need to run more handlers. */ DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect - see if other handlers want it. */ DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */ } DBusHandlerResult; /* Bus names */ /** The bus name used to talk to the bus itself. */ #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" /* Paths */ /** The object path used to talk to the bus itself. */ #define DBUS_PATH_DBUS "/org/freedesktop/DBus" /** The object path used in local/in-process-generated messages. */ #define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local" /* Interfaces, these #define don't do much other than * catch typos at compile time */ /** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */ #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" /** The monitoring interface exported by the dbus-daemon */ #define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring" /** The verbose interface exported by the dbus-daemon */ #define DBUS_INTERFACE_VERBOSE "org.freedesktop.DBus.Verbose" /** The interface supported by introspectable objects */ #define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" /** The interface supported by objects with properties */ #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" /** The interface supported by most dbus peers */ #define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer" /** This is a special interface whose methods can only be invoked * by the local implementation (messages from remote apps aren't * allowed to specify this interface). */ #define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local" /* Owner flags */ #define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */ #define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */ #define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 /**< If we can not become the primary owner do not place us in the queue */ /* Replies to request for a name */ #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 /**< Service has become the primary owner of the requested name */ #define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 /**< Service could not become the primary owner and has been placed in the queue */ #define DBUS_REQUEST_NAME_REPLY_EXISTS 3 /**< Service is already in the queue */ #define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 /**< Service is already the primary owner */ /* Replies to releasing a name */ #define DBUS_RELEASE_NAME_REPLY_RELEASED 1 /**< Service was released from the given name */ #define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 /**< The given name does not exist on the bus */ #define DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 /**< Service is not an owner of the given name */ /* Replies to service starts */ #define DBUS_START_REPLY_SUCCESS 1 /**< Service was auto started */ #define DBUS_START_REPLY_ALREADY_RUNNING 2 /**< Service was already running */ /** @} */ #ifdef __cplusplus #if 0 { /* avoids confusing emacs indentation */ #endif } #endif #endif /* DBUS_SHARED_H */ dbus-1.10.6/dbus/dbus-server.h0000644000175000017500000001127212602773110016107 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-server.h DBusServer object * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_SERVER_H #define DBUS_SERVER_H #include #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusServer * @{ */ typedef struct DBusServer DBusServer; /** Called when a new connection to the server is available. Must reference and save the new * connection, or close the new connection. Set with dbus_server_set_new_connection_function(). */ typedef void (* DBusNewConnectionFunction) (DBusServer *server, DBusConnection *new_connection, void *data); DBUS_EXPORT DBusServer* dbus_server_listen (const char *address, DBusError *error); DBUS_EXPORT DBusServer* dbus_server_ref (DBusServer *server); DBUS_EXPORT void dbus_server_unref (DBusServer *server); DBUS_EXPORT void dbus_server_disconnect (DBusServer *server); DBUS_EXPORT dbus_bool_t dbus_server_get_is_connected (DBusServer *server); DBUS_EXPORT char* dbus_server_get_address (DBusServer *server); DBUS_EXPORT char* dbus_server_get_id (DBusServer *server); DBUS_EXPORT void dbus_server_set_new_connection_function (DBusServer *server, DBusNewConnectionFunction function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_server_set_watch_functions (DBusServer *server, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_server_set_timeout_functions (DBusServer *server, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer *server, const char **mechanisms); DBUS_EXPORT dbus_bool_t dbus_server_allocate_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT void dbus_server_free_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT dbus_bool_t dbus_server_set_data (DBusServer *server, int slot, void *data, DBusFreeFunction free_data_func); DBUS_EXPORT void* dbus_server_get_data (DBusServer *server, int slot); /** @} */ DBUS_END_DECLS #endif /* DBUS_SERVER_H */ dbus-1.10.6/dbus/dbus-protocol.h0000644000175000017500000005613212602773110016446 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-protocol.h D-Bus protocol constants * * Copyright (C) 2002, 2003 CodeFactory AB * Copyright (C) 2004, 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_PROTOCOL_H #define DBUS_PROTOCOL_H /* Don't include anything in here from anywhere else. It's * intended for use by any random library. */ #ifdef __cplusplus extern "C" { #if 0 } /* avoids confusing emacs indentation */ #endif #endif /* Normally docs are in .c files, but there isn't a .c file for this. */ /** * @defgroup DBusProtocol Protocol constants * @ingroup DBus * * @brief Defines constants which are part of the D-Bus protocol * * This header is intended for use by any library, not only libdbus. * * @{ */ /* Message byte order */ #define DBUS_LITTLE_ENDIAN ('l') /**< Code marking LSB-first byte order in the wire protocol. */ #define DBUS_BIG_ENDIAN ('B') /**< Code marking MSB-first byte order in the wire protocol. */ /** Protocol version. */ #define DBUS_MAJOR_PROTOCOL_VERSION 1 /** Type code that is never equal to a legitimate type code */ #define DBUS_TYPE_INVALID ((int) '\0') /** #DBUS_TYPE_INVALID as a string literal instead of a int literal */ #define DBUS_TYPE_INVALID_AS_STRING "\0" /* Primitive types */ /** Type code marking an 8-bit unsigned integer */ #define DBUS_TYPE_BYTE ((int) 'y') /** #DBUS_TYPE_BYTE as a string literal instead of a int literal */ #define DBUS_TYPE_BYTE_AS_STRING "y" /** Type code marking a boolean */ #define DBUS_TYPE_BOOLEAN ((int) 'b') /** #DBUS_TYPE_BOOLEAN as a string literal instead of a int literal */ #define DBUS_TYPE_BOOLEAN_AS_STRING "b" /** Type code marking a 16-bit signed integer */ #define DBUS_TYPE_INT16 ((int) 'n') /** #DBUS_TYPE_INT16 as a string literal instead of a int literal */ #define DBUS_TYPE_INT16_AS_STRING "n" /** Type code marking a 16-bit unsigned integer */ #define DBUS_TYPE_UINT16 ((int) 'q') /** #DBUS_TYPE_UINT16 as a string literal instead of a int literal */ #define DBUS_TYPE_UINT16_AS_STRING "q" /** Type code marking a 32-bit signed integer */ #define DBUS_TYPE_INT32 ((int) 'i') /** #DBUS_TYPE_INT32 as a string literal instead of a int literal */ #define DBUS_TYPE_INT32_AS_STRING "i" /** Type code marking a 32-bit unsigned integer */ #define DBUS_TYPE_UINT32 ((int) 'u') /** #DBUS_TYPE_UINT32 as a string literal instead of a int literal */ #define DBUS_TYPE_UINT32_AS_STRING "u" /** Type code marking a 64-bit signed integer */ #define DBUS_TYPE_INT64 ((int) 'x') /** #DBUS_TYPE_INT64 as a string literal instead of a int literal */ #define DBUS_TYPE_INT64_AS_STRING "x" /** Type code marking a 64-bit unsigned integer */ #define DBUS_TYPE_UINT64 ((int) 't') /** #DBUS_TYPE_UINT64 as a string literal instead of a int literal */ #define DBUS_TYPE_UINT64_AS_STRING "t" /** Type code marking an 8-byte double in IEEE 754 format */ #define DBUS_TYPE_DOUBLE ((int) 'd') /** #DBUS_TYPE_DOUBLE as a string literal instead of a int literal */ #define DBUS_TYPE_DOUBLE_AS_STRING "d" /** Type code marking a UTF-8 encoded, nul-terminated Unicode string */ #define DBUS_TYPE_STRING ((int) 's') /** #DBUS_TYPE_STRING as a string literal instead of a int literal */ #define DBUS_TYPE_STRING_AS_STRING "s" /** Type code marking a D-Bus object path */ #define DBUS_TYPE_OBJECT_PATH ((int) 'o') /** #DBUS_TYPE_OBJECT_PATH as a string literal instead of a int literal */ #define DBUS_TYPE_OBJECT_PATH_AS_STRING "o" /** Type code marking a D-Bus type signature */ #define DBUS_TYPE_SIGNATURE ((int) 'g') /** #DBUS_TYPE_SIGNATURE as a string literal instead of a int literal */ #define DBUS_TYPE_SIGNATURE_AS_STRING "g" /** Type code marking a unix file descriptor */ #define DBUS_TYPE_UNIX_FD ((int) 'h') /** #DBUS_TYPE_UNIX_FD as a string literal instead of a int literal */ #define DBUS_TYPE_UNIX_FD_AS_STRING "h" /* Compound types */ /** Type code marking a D-Bus array type */ #define DBUS_TYPE_ARRAY ((int) 'a') /** #DBUS_TYPE_ARRAY as a string literal instead of a int literal */ #define DBUS_TYPE_ARRAY_AS_STRING "a" /** Type code marking a D-Bus variant type */ #define DBUS_TYPE_VARIANT ((int) 'v') /** #DBUS_TYPE_VARIANT as a string literal instead of a int literal */ #define DBUS_TYPE_VARIANT_AS_STRING "v" /** STRUCT and DICT_ENTRY are sort of special since their codes can't * appear in a type string, instead * DBUS_STRUCT_BEGIN_CHAR/DBUS_DICT_ENTRY_BEGIN_CHAR have to appear */ /** Type code used to represent a struct; however, this type code does not appear * in type signatures, instead #DBUS_STRUCT_BEGIN_CHAR and #DBUS_STRUCT_END_CHAR will * appear in a signature. */ #define DBUS_TYPE_STRUCT ((int) 'r') /** #DBUS_TYPE_STRUCT as a string literal instead of a int literal */ #define DBUS_TYPE_STRUCT_AS_STRING "r" /** Type code used to represent a dict entry; however, this type code does not appear * in type signatures, instead #DBUS_DICT_ENTRY_BEGIN_CHAR and #DBUS_DICT_ENTRY_END_CHAR will * appear in a signature. */ #define DBUS_TYPE_DICT_ENTRY ((int) 'e') /** #DBUS_TYPE_DICT_ENTRY as a string literal instead of a int literal */ #define DBUS_TYPE_DICT_ENTRY_AS_STRING "e" /** Does not include #DBUS_TYPE_INVALID, #DBUS_STRUCT_BEGIN_CHAR, #DBUS_STRUCT_END_CHAR, * #DBUS_DICT_ENTRY_BEGIN_CHAR, or #DBUS_DICT_ENTRY_END_CHAR - i.e. it is the number of * valid types, not the number of distinct characters that may appear in a type signature. */ #define DBUS_NUMBER_OF_TYPES (16) /* characters other than typecodes that appear in type signatures */ /** Code marking the start of a struct type in a type signature */ #define DBUS_STRUCT_BEGIN_CHAR ((int) '(') /** #DBUS_STRUCT_BEGIN_CHAR as a string literal instead of a int literal */ #define DBUS_STRUCT_BEGIN_CHAR_AS_STRING "(" /** Code marking the end of a struct type in a type signature */ #define DBUS_STRUCT_END_CHAR ((int) ')') /** #DBUS_STRUCT_END_CHAR a string literal instead of a int literal */ #define DBUS_STRUCT_END_CHAR_AS_STRING ")" /** Code marking the start of a dict entry type in a type signature */ #define DBUS_DICT_ENTRY_BEGIN_CHAR ((int) '{') /** #DBUS_DICT_ENTRY_BEGIN_CHAR as a string literal instead of a int literal */ #define DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING "{" /** Code marking the end of a dict entry type in a type signature */ #define DBUS_DICT_ENTRY_END_CHAR ((int) '}') /** #DBUS_DICT_ENTRY_END_CHAR as a string literal instead of a int literal */ #define DBUS_DICT_ENTRY_END_CHAR_AS_STRING "}" /** Max length in bytes of a bus name, interface, or member (not object * path, paths are unlimited). This is limited because lots of stuff * is O(n) in this number, plus it would be obnoxious to type in a * paragraph-long method name so most likely something like that would * be an exploit. */ #define DBUS_MAXIMUM_NAME_LENGTH 255 /** This one is 255 so it fits in a byte */ #define DBUS_MAXIMUM_SIGNATURE_LENGTH 255 /** Max length of a match rule string; to keep people from hosing the * daemon with some huge rule */ #define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 /** Max arg number you can match on in a match rule, e.g. * arg0='hello' is OK, arg3489720987='hello' is not */ #define DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER 63 /** Max length of a marshaled array in bytes (64M, 2^26) We use signed * int for lengths so must be INT_MAX or less. We need something a * bit smaller than INT_MAX because the array is inside a message with * header info, etc. so an INT_MAX array wouldn't allow the message * overhead. The 64M number is an attempt at a larger number than * we'd reasonably ever use, but small enough that your bus would chew * through it fairly quickly without locking up forever. If you have * data that's likely to be larger than this, you should probably be * sending it in multiple incremental messages anyhow. */ #define DBUS_MAXIMUM_ARRAY_LENGTH (67108864) /** Number of bits you need in an unsigned to store the max array size */ #define DBUS_MAXIMUM_ARRAY_LENGTH_BITS 26 /** The maximum total message size including header and body; similar * rationale to max array size. */ #define DBUS_MAXIMUM_MESSAGE_LENGTH (DBUS_MAXIMUM_ARRAY_LENGTH * 2) /** Number of bits you need in an unsigned to store the max message size */ #define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27 /** The maximum total number of unix fds in a message. Similar * rationale as DBUS_MAXIMUM_MESSAGE_LENGTH. However we divide by four * given that one fd is an int and hence at least 32 bits. */ #define DBUS_MAXIMUM_MESSAGE_UNIX_FDS (DBUS_MAXIMUM_MESSAGE_LENGTH/4) /** Number of bits you need in an unsigned to store the max message unix fds */ #define DBUS_MAXIMUM_MESSAGE_UNIX_FDS_BITS (DBUS_MAXIMUM_MESSAGE_LENGTH_BITS-2) /** Depth of recursion in the type tree. This is automatically limited * to DBUS_MAXIMUM_SIGNATURE_LENGTH since you could only have an array * of array of array of ... that fit in the max signature. But that's * probably a bit too large. */ #define DBUS_MAXIMUM_TYPE_RECURSION_DEPTH 32 /* Types of message */ /** This value is never a valid message type, see dbus_message_get_type() */ #define DBUS_MESSAGE_TYPE_INVALID 0 /** Message type of a method call message, see dbus_message_get_type() */ #define DBUS_MESSAGE_TYPE_METHOD_CALL 1 /** Message type of a method return message, see dbus_message_get_type() */ #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 /** Message type of an error reply message, see dbus_message_get_type() */ #define DBUS_MESSAGE_TYPE_ERROR 3 /** Message type of a signal message, see dbus_message_get_type() */ #define DBUS_MESSAGE_TYPE_SIGNAL 4 #define DBUS_NUM_MESSAGE_TYPES 5 /* Header flags */ /** If set, this flag means that the sender of a message does not care about getting * a reply, so the recipient need not send one. See dbus_message_set_no_reply(). */ #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 /** * If set, this flag means that even if the message bus knows how to start an owner for * the destination bus name (see dbus_message_set_destination()), it should not * do so. If this flag is not set, the bus may launch a program to process the * message. */ #define DBUS_HEADER_FLAG_NO_AUTO_START 0x2 /** * If set on a method call, this flag means that the caller is prepared to * wait for interactive authorization. */ #define DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION 0x4 /* Header fields */ /** Not equal to any valid header field code */ #define DBUS_HEADER_FIELD_INVALID 0 /** Header field code for the path - the path is the object emitting a signal or the object receiving a method call. * See dbus_message_set_path(). */ #define DBUS_HEADER_FIELD_PATH 1 /** Header field code for the interface containing a member (method or signal). * See dbus_message_set_interface(). */ #define DBUS_HEADER_FIELD_INTERFACE 2 /** Header field code for a member (method or signal). See dbus_message_set_member(). */ #define DBUS_HEADER_FIELD_MEMBER 3 /** Header field code for an error name (found in #DBUS_MESSAGE_TYPE_ERROR messages). * See dbus_message_set_error_name(). */ #define DBUS_HEADER_FIELD_ERROR_NAME 4 /** Header field code for a reply serial, used to match a #DBUS_MESSAGE_TYPE_METHOD_RETURN message with the * message that it's a reply to. See dbus_message_set_reply_serial(). */ #define DBUS_HEADER_FIELD_REPLY_SERIAL 5 /** * Header field code for the destination bus name of a message. See dbus_message_set_destination(). */ #define DBUS_HEADER_FIELD_DESTINATION 6 /** * Header field code for the sender of a message; usually initialized by the message bus. * See dbus_message_set_sender(). */ #define DBUS_HEADER_FIELD_SENDER 7 /** * Header field code for the type signature of a message. */ #define DBUS_HEADER_FIELD_SIGNATURE 8 /** * Header field code for the number of unix file descriptors associated * with this message. */ #define DBUS_HEADER_FIELD_UNIX_FDS 9 /** * Value of the highest-numbered header field code, can be used to determine * the size of an array indexed by header field code. Remember though * that unknown codes must be ignored, so check for that before * indexing the array. */ #define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_UNIX_FDS /** Header format is defined as a signature: * byte byte order * byte message type ID * byte flags * byte protocol version * uint32 body length * uint32 serial * array of struct (byte,variant) (field name, value) * * The length of the header can be computed as the * fixed size of the initial data, plus the length of * the array at the end, plus padding to an 8-boundary. */ #define DBUS_HEADER_SIGNATURE \ DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_UINT32_AS_STRING \ DBUS_TYPE_UINT32_AS_STRING \ DBUS_TYPE_ARRAY_AS_STRING \ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \ DBUS_TYPE_BYTE_AS_STRING \ DBUS_TYPE_VARIANT_AS_STRING \ DBUS_STRUCT_END_CHAR_AS_STRING /** * The smallest header size that can occur. (It won't be valid due to * missing required header fields.) This is 4 bytes, two uint32, an * array length. This isn't any kind of resource limit, just the * necessary/logical outcome of the header signature. */ #define DBUS_MINIMUM_HEADER_SIZE 16 /* Errors */ /* WARNING these get autoconverted to an enum in dbus-glib.h. Thus, * if you change the order it breaks the ABI. Keep them in order. * Also, don't change the formatting since that will break the sed * script. */ /** A generic error; "something went wrong" - see the error message for more. */ #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" /** There was not enough memory to complete an operation. */ #define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" /** The bus doesn't know how to launch a service to supply the bus name you wanted. */ #define DBUS_ERROR_SERVICE_UNKNOWN "org.freedesktop.DBus.Error.ServiceUnknown" /** The bus name you referenced doesn't exist (i.e. no application owns it). */ #define DBUS_ERROR_NAME_HAS_NO_OWNER "org.freedesktop.DBus.Error.NameHasNoOwner" /** No reply to a message expecting one, usually means a timeout occurred. */ #define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply" /** Something went wrong reading or writing to a socket, for example. */ #define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError" /** A D-Bus bus address was malformed. */ #define DBUS_ERROR_BAD_ADDRESS "org.freedesktop.DBus.Error.BadAddress" /** Requested operation isn't supported (like ENOSYS on UNIX). */ #define DBUS_ERROR_NOT_SUPPORTED "org.freedesktop.DBus.Error.NotSupported" /** Some limited resource is exhausted. */ #define DBUS_ERROR_LIMITS_EXCEEDED "org.freedesktop.DBus.Error.LimitsExceeded" /** Security restrictions don't allow doing what you're trying to do. */ #define DBUS_ERROR_ACCESS_DENIED "org.freedesktop.DBus.Error.AccessDenied" /** Authentication didn't work. */ #define DBUS_ERROR_AUTH_FAILED "org.freedesktop.DBus.Error.AuthFailed" /** Unable to connect to server (probably caused by ECONNREFUSED on a socket). */ #define DBUS_ERROR_NO_SERVER "org.freedesktop.DBus.Error.NoServer" /** Certain timeout errors, possibly ETIMEDOUT on a socket. * Note that #DBUS_ERROR_NO_REPLY is used for message reply timeouts. * @warning this is confusingly-named given that #DBUS_ERROR_TIMED_OUT also exists. We can't fix * it for compatibility reasons so just be careful. */ #define DBUS_ERROR_TIMEOUT "org.freedesktop.DBus.Error.Timeout" /** No network access (probably ENETUNREACH on a socket). */ #define DBUS_ERROR_NO_NETWORK "org.freedesktop.DBus.Error.NoNetwork" /** Can't bind a socket since its address is in use (i.e. EADDRINUSE). */ #define DBUS_ERROR_ADDRESS_IN_USE "org.freedesktop.DBus.Error.AddressInUse" /** The connection is disconnected and you're trying to use it. */ #define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected" /** Invalid arguments passed to a method call. */ #define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" /** Missing file. */ #define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" /** Existing file and the operation you're using does not silently overwrite. */ #define DBUS_ERROR_FILE_EXISTS "org.freedesktop.DBus.Error.FileExists" /** Method name you invoked isn't known by the object you invoked it on. */ #define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" /** Object you invoked a method on isn't known. */ #define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" /** Interface you invoked a method on isn't known by the object. */ #define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" /** Property you tried to access isn't known by the object. */ #define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" /** Property you tried to set is read-only. */ #define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" /** Certain timeout errors, e.g. while starting a service. * @warning this is confusingly-named given that #DBUS_ERROR_TIMEOUT also exists. We can't fix * it for compatibility reasons so just be careful. */ #define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut" /** Tried to remove or modify a match rule that didn't exist. */ #define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound" /** The match rule isn't syntactically valid. */ #define DBUS_ERROR_MATCH_RULE_INVALID "org.freedesktop.DBus.Error.MatchRuleInvalid" /** While starting a new process, the exec() call failed. */ #define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed" /** While starting a new process, the fork() call failed. */ #define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed" /** While starting a new process, the child exited with a status code. */ #define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited" /** While starting a new process, the child exited on a signal. */ #define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled" /** While starting a new process, something went wrong. */ #define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed" /** We failed to setup the environment correctly. */ #define DBUS_ERROR_SPAWN_SETUP_FAILED "org.freedesktop.DBus.Error.Spawn.FailedToSetup" /** We failed to setup the config parser correctly. */ #define DBUS_ERROR_SPAWN_CONFIG_INVALID "org.freedesktop.DBus.Error.Spawn.ConfigInvalid" /** Bus name was not valid. */ #define DBUS_ERROR_SPAWN_SERVICE_INVALID "org.freedesktop.DBus.Error.Spawn.ServiceNotValid" /** Service file not found in system-services directory. */ #define DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.Spawn.ServiceNotFound" /** Permissions are incorrect on the setuid helper. */ #define DBUS_ERROR_SPAWN_PERMISSIONS_INVALID "org.freedesktop.DBus.Error.Spawn.PermissionsInvalid" /** Service file invalid (Name, User or Exec missing). */ #define DBUS_ERROR_SPAWN_FILE_INVALID "org.freedesktop.DBus.Error.Spawn.FileInvalid" /** Tried to get a UNIX process ID and it wasn't available. */ #define DBUS_ERROR_SPAWN_NO_MEMORY "org.freedesktop.DBus.Error.Spawn.NoMemory" /** Tried to get a UNIX process ID and it wasn't available. */ #define DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN "org.freedesktop.DBus.Error.UnixProcessIdUnknown" /** A type signature is not valid. */ #define DBUS_ERROR_INVALID_SIGNATURE "org.freedesktop.DBus.Error.InvalidSignature" /** A file contains invalid syntax or is otherwise broken. */ #define DBUS_ERROR_INVALID_FILE_CONTENT "org.freedesktop.DBus.Error.InvalidFileContent" /** Asked for SELinux security context and it wasn't available. */ #define DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown" /** Asked for ADT audit data and it wasn't available. */ #define DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN "org.freedesktop.DBus.Error.AdtAuditDataUnknown" /** There's already an object with the requested object path. */ #define DBUS_ERROR_OBJECT_PATH_IN_USE "org.freedesktop.DBus.Error.ObjectPathInUse" /** The message meta data does not match the payload. e.g. expected number of file descriptors were not sent over the socket this message was received on. */ #define DBUS_ERROR_INCONSISTENT_MESSAGE "org.freedesktop.DBus.Error.InconsistentMessage" /** The message is not allowed without performing interactive authorization, * but could have succeeded if an interactive authorization step was * allowed. */ #define DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired" /* XML introspection format */ /** XML namespace of the introspection format version 1.0 */ #define DBUS_INTROSPECT_1_0_XML_NAMESPACE "http://www.freedesktop.org/standards/dbus" /** XML public identifier of the introspection format version 1.0 */ #define DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" /** XML system identifier of the introspection format version 1.0 */ #define DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" /** XML document type declaration of the introspection format version 1.0 */ #define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "\n" /** @} */ #ifdef __cplusplus #if 0 { /* avoids confusing emacs indentation */ #endif } #endif #endif /* DBUS_PROTOCOL_H */ dbus-1.10.6/dbus/dbus-pending-call.h0000644000175000017500000000606412602773110017141 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-pending-call.h Object representing a call in progress. * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_PENDING_CALL_H #define DBUS_PENDING_CALL_H #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusPendingCall * @{ */ #define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff) #define DBUS_TIMEOUT_USE_DEFAULT (-1) DBUS_EXPORT DBusPendingCall* dbus_pending_call_ref (DBusPendingCall *pending); DBUS_EXPORT void dbus_pending_call_unref (DBusPendingCall *pending); DBUS_EXPORT dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data); DBUS_EXPORT void dbus_pending_call_cancel (DBusPendingCall *pending); DBUS_EXPORT dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending); DBUS_EXPORT DBusMessage* dbus_pending_call_steal_reply (DBusPendingCall *pending); DBUS_EXPORT void dbus_pending_call_block (DBusPendingCall *pending); DBUS_EXPORT dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func); DBUS_EXPORT void* dbus_pending_call_get_data (DBusPendingCall *pending, dbus_int32_t slot); /** @} */ DBUS_END_DECLS #endif /* DBUS_PENDING_CALL_H */ dbus-1.10.6/dbus/dbus-misc.h0000644000175000017500000000332012602773110015527 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-misc.h A few assorted public functions that don't fit elsewhere * * Copyright (C) 2006 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_MISC_H #define DBUS_MISC_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusMisc * @{ */ DBUS_EXPORT char* dbus_get_local_machine_id (void); DBUS_EXPORT void dbus_get_version (int *major_version_p, int *minor_version_p, int *micro_version_p); DBUS_EXPORT dbus_bool_t dbus_setenv (const char *variable, const char *value); /** @} */ DBUS_END_DECLS #endif /* DBUS_MISC_H */ dbus-1.10.6/dbus/dbus-message.h0000644000175000017500000003201012602773110016216 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message.h DBusMessage object * * Copyright (C) 2002, 2003, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_MESSAGE_H #define DBUS_MESSAGE_H #include #include #include #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusMessage * @{ */ typedef struct DBusMessage DBusMessage; /** Opaque type representing a message iterator. Can be copied by value, and contains no allocated memory so never needs to be freed and can be allocated on the stack. */ typedef struct DBusMessageIter DBusMessageIter; /** * DBusMessageIter struct; contains no public fields. */ struct DBusMessageIter { void *dummy1; /**< Don't use this */ void *dummy2; /**< Don't use this */ dbus_uint32_t dummy3; /**< Don't use this */ int dummy4; /**< Don't use this */ int dummy5; /**< Don't use this */ int dummy6; /**< Don't use this */ int dummy7; /**< Don't use this */ int dummy8; /**< Don't use this */ int dummy9; /**< Don't use this */ int dummy10; /**< Don't use this */ int dummy11; /**< Don't use this */ int pad1; /**< Don't use this */ int pad2; /**< Don't use this */ void *pad3; /**< Don't use this */ }; DBUS_EXPORT DBusMessage* dbus_message_new (int message_type); DBUS_EXPORT DBusMessage* dbus_message_new_method_call (const char *bus_name, const char *path, const char *iface, const char *method); DBUS_EXPORT DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); DBUS_EXPORT DBusMessage* dbus_message_new_signal (const char *path, const char *iface, const char *name); DBUS_EXPORT DBusMessage* dbus_message_new_error (DBusMessage *reply_to, const char *error_name, const char *error_message); DBUS_EXPORT DBusMessage* dbus_message_new_error_printf (DBusMessage *reply_to, const char *error_name, const char *error_format, ...); DBUS_EXPORT DBusMessage* dbus_message_copy (const DBusMessage *message); DBUS_EXPORT DBusMessage* dbus_message_ref (DBusMessage *message); DBUS_EXPORT void dbus_message_unref (DBusMessage *message); DBUS_EXPORT int dbus_message_get_type (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_set_path (DBusMessage *message, const char *object_path); DBUS_EXPORT const char* dbus_message_get_path (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_has_path (DBusMessage *message, const char *object_path); DBUS_EXPORT dbus_bool_t dbus_message_set_interface (DBusMessage *message, const char *iface); DBUS_EXPORT const char* dbus_message_get_interface (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_has_interface (DBusMessage *message, const char *iface); DBUS_EXPORT dbus_bool_t dbus_message_set_member (DBusMessage *message, const char *member); DBUS_EXPORT const char* dbus_message_get_member (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_has_member (DBusMessage *message, const char *member); DBUS_EXPORT dbus_bool_t dbus_message_set_error_name (DBusMessage *message, const char *name); DBUS_EXPORT const char* dbus_message_get_error_name (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_set_destination (DBusMessage *message, const char *destination); DBUS_EXPORT const char* dbus_message_get_destination (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_set_sender (DBusMessage *message, const char *sender); DBUS_EXPORT const char* dbus_message_get_sender (DBusMessage *message); DBUS_EXPORT const char* dbus_message_get_signature (DBusMessage *message); DBUS_EXPORT void dbus_message_set_no_reply (DBusMessage *message, dbus_bool_t no_reply); DBUS_EXPORT dbus_bool_t dbus_message_get_no_reply (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_is_method_call (DBusMessage *message, const char *iface, const char *method); DBUS_EXPORT dbus_bool_t dbus_message_is_signal (DBusMessage *message, const char *iface, const char *signal_name); DBUS_EXPORT dbus_bool_t dbus_message_is_error (DBusMessage *message, const char *error_name); DBUS_EXPORT dbus_bool_t dbus_message_has_destination (DBusMessage *message, const char *bus_name); DBUS_EXPORT dbus_bool_t dbus_message_has_sender (DBusMessage *message, const char *unique_bus_name); DBUS_EXPORT dbus_bool_t dbus_message_has_signature (DBusMessage *message, const char *signature); DBUS_EXPORT dbus_uint32_t dbus_message_get_serial (DBusMessage *message); DBUS_EXPORT void dbus_message_set_serial (DBusMessage *message, dbus_uint32_t serial); DBUS_EXPORT dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message, dbus_uint32_t reply_serial); DBUS_EXPORT dbus_uint32_t dbus_message_get_reply_serial (DBusMessage *message); DBUS_EXPORT void dbus_message_set_auto_start (DBusMessage *message, dbus_bool_t auto_start); DBUS_EXPORT dbus_bool_t dbus_message_get_auto_start (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message, char ***path); DBUS_EXPORT dbus_bool_t dbus_message_append_args (DBusMessage *message, int first_arg_type, ...); DBUS_EXPORT dbus_bool_t dbus_message_append_args_valist (DBusMessage *message, int first_arg_type, va_list var_args); DBUS_EXPORT dbus_bool_t dbus_message_get_args (DBusMessage *message, DBusError *error, int first_arg_type, ...); DBUS_EXPORT dbus_bool_t dbus_message_get_args_valist (DBusMessage *message, DBusError *error, int first_arg_type, va_list var_args); DBUS_EXPORT dbus_bool_t dbus_message_contains_unix_fds (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_iter_init (DBusMessage *message, DBusMessageIter *iter); DBUS_EXPORT dbus_bool_t dbus_message_iter_has_next (DBusMessageIter *iter); DBUS_EXPORT dbus_bool_t dbus_message_iter_next (DBusMessageIter *iter); DBUS_EXPORT char* dbus_message_iter_get_signature (DBusMessageIter *iter); DBUS_EXPORT int dbus_message_iter_get_arg_type (DBusMessageIter *iter); DBUS_EXPORT int dbus_message_iter_get_element_type (DBusMessageIter *iter); DBUS_EXPORT void dbus_message_iter_recurse (DBusMessageIter *iter, DBusMessageIter *sub); DBUS_EXPORT void dbus_message_iter_get_basic (DBusMessageIter *iter, void *value); DBUS_EXPORT int dbus_message_iter_get_element_count(DBusMessageIter *iter); #ifndef DBUS_DISABLE_DEPRECATED /* This function returns the wire protocol size of the array in bytes, * you do not want to know that probably */ DBUS_EXPORT DBUS_DEPRECATED int dbus_message_iter_get_array_len (DBusMessageIter *iter); #endif DBUS_EXPORT void dbus_message_iter_get_fixed_array (DBusMessageIter *iter, void *value, int *n_elements); DBUS_EXPORT void dbus_message_iter_init_append (DBusMessage *message, DBusMessageIter *iter); DBUS_EXPORT dbus_bool_t dbus_message_iter_append_basic (DBusMessageIter *iter, int type, const void *value); DBUS_EXPORT dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter *iter, int element_type, const void *value, int n_elements); DBUS_EXPORT dbus_bool_t dbus_message_iter_open_container (DBusMessageIter *iter, int type, const char *contained_signature, DBusMessageIter *sub); DBUS_EXPORT dbus_bool_t dbus_message_iter_close_container (DBusMessageIter *iter, DBusMessageIter *sub); DBUS_EXPORT void dbus_message_iter_abandon_container (DBusMessageIter *iter, DBusMessageIter *sub); DBUS_EXPORT void dbus_message_lock (DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_set_error_from_message (DBusError *error, DBusMessage *message); DBUS_EXPORT dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT void dbus_message_free_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT dbus_bool_t dbus_message_set_data (DBusMessage *message, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func); DBUS_EXPORT void* dbus_message_get_data (DBusMessage *message, dbus_int32_t slot); DBUS_EXPORT int dbus_message_type_from_string (const char *type_str); DBUS_EXPORT const char* dbus_message_type_to_string (int type); DBUS_EXPORT dbus_bool_t dbus_message_marshal (DBusMessage *msg, char **marshalled_data_p, int *len_p); DBUS_EXPORT DBusMessage* dbus_message_demarshal (const char *str, int len, DBusError *error); DBUS_EXPORT int dbus_message_demarshal_bytes_needed (const char *str, int len); DBUS_EXPORT void dbus_message_set_allow_interactive_authorization (DBusMessage *message, dbus_bool_t allow); DBUS_EXPORT dbus_bool_t dbus_message_get_allow_interactive_authorization ( DBusMessage *message); /** @} */ DBUS_END_DECLS #endif /* DBUS_MESSAGE_H */ dbus-1.10.6/dbus/dbus-memory.h0000644000175000017500000000366712602773110016122 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-memory.h D-Bus memory handling * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_MEMORY_H #define DBUS_MEMORY_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusMemory * @{ */ DBUS_EXPORT DBUS_MALLOC DBUS_ALLOC_SIZE(1) void* dbus_malloc (size_t bytes); DBUS_EXPORT DBUS_MALLOC DBUS_ALLOC_SIZE(1) void* dbus_malloc0 (size_t bytes); DBUS_EXPORT DBUS_MALLOC DBUS_ALLOC_SIZE(2) void* dbus_realloc (void *memory, size_t bytes); DBUS_EXPORT void dbus_free (void *memory); #define dbus_new(type, count) ((type*)dbus_malloc (sizeof (type) * (count))) #define dbus_new0(type, count) ((type*)dbus_malloc0 (sizeof (type) * (count))) DBUS_EXPORT void dbus_free_string_array (char **str_array); typedef void (* DBusFreeFunction) (void *memory); DBUS_EXPORT void dbus_shutdown (void); /** @} */ DBUS_END_DECLS #endif /* DBUS_MEMORY_H */ dbus-1.10.6/dbus/dbus-macros.h0000644000175000017500000001360512602773110016067 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-macros.h generic macros * * Copyright (C) 2002 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_MACROS_H #define DBUS_MACROS_H #ifdef __cplusplus # define DBUS_BEGIN_DECLS extern "C" { # define DBUS_END_DECLS } #else # define DBUS_BEGIN_DECLS # define DBUS_END_DECLS #endif #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif #ifndef NULL # ifdef __cplusplus # define NULL (0L) # else /* !__cplusplus */ # define NULL ((void*) 0) # endif /* !__cplusplus */ #endif #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) # define DBUS_DEPRECATED __attribute__ ((__deprecated__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1300) # define DBUS_DEPRECATED __declspec(deprecated) #else # define DBUS_DEPRECATED #endif #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) # define _DBUS_GNUC_EXTENSION __extension__ #else # define _DBUS_GNUC_EXTENSION #endif #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) #define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) \ __attribute__((__format__ (__printf__, format_idx, arg_idx))) #define _DBUS_GNUC_NORETURN \ __attribute__((__noreturn__)) #define _DBUS_GNUC_UNUSED \ __attribute__((__unused__)) #else /* !__GNUC__ */ #define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) #define _DBUS_GNUC_NORETURN #define _DBUS_GNUC_UNUSED #endif /* !__GNUC__ */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) #define DBUS_MALLOC __attribute__((__malloc__)) #else #define DBUS_MALLOC #endif #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) #define DBUS_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) #define DBUS_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y))) #else #define DBUS_ALLOC_SIZE(x) #define DBUS_ALLOC_SIZE2(x,y) #endif #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define _DBUS_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define _DBUS_GNUC_WARN_UNUSED_RESULT #endif /** @def _DBUS_GNUC_PRINTF * used to tell gcc about printf format strings */ /** @def _DBUS_GNUC_NORETURN * used to tell gcc about functions that never return, such as _dbus_abort() */ /** @def _DBUS_GNUC_WARN_UNUSED_RESULT * used to tell gcc about functions whose result must be used */ /* Normally docs are in .c files, but there isn't a .c file for this. */ /** * @defgroup DBusMacros Utility macros * @ingroup DBus * @brief #TRUE, #FALSE, #NULL, and so on * * Utility macros. * * @{ */ /** * @def DBUS_BEGIN_DECLS * * Macro used prior to declaring functions in the D-Bus header * files. Expands to "extern "C"" when using a C++ compiler, * and expands to nothing when using a C compiler. * * Please don't use this in your own code, consider it * D-Bus internal. */ /** * @def DBUS_END_DECLS * * Macro used after declaring functions in the D-Bus header * files. Expands to "}" when using a C++ compiler, * and expands to nothing when using a C compiler. * * Please don't use this in your own code, consider it * D-Bus internal. */ /** * @def TRUE * * Expands to "1" */ /** * @def FALSE * * Expands to "0" */ /** * @def NULL * * A null pointer, defined appropriately for C or C++. */ /** * @def DBUS_DEPRECATED * * Tells the compiler to warn about a function or type if it's used. * Code marked in this way should also be enclosed in * @code * #ifndef DBUS_DISABLE_DEPRECATED * deprecated stuff here * #endif * @endcode * * Please don't use this in your own code, consider it * D-Bus internal. */ /** * @def _DBUS_GNUC_EXTENSION * * Tells gcc not to warn about extensions to the C standard in the * following expression, even if compiling with -pedantic. Do not use * this macro in your own code; please consider it to be internal to libdbus. */ /* * @def DBUS_EXPORT * * Declare the following symbol as public. This is currently a noop on * platforms other than Windows. */ #if defined(DBUS_EXPORT) /* value forced by compiler command line, don't redefine */ #elif defined(_WIN32) # if defined(DBUS_STATIC_BUILD) # define DBUS_EXPORT # elif defined(dbus_1_EXPORTS) # define DBUS_EXPORT __declspec(dllexport) # else # define DBUS_EXPORT __declspec(dllimport) # endif #elif defined(__GNUC__) && __GNUC__ >= 4 # define DBUS_EXPORT __attribute__ ((__visibility__ ("default"))) #else #define DBUS_EXPORT #endif #if defined(DBUS_PRIVATE_EXPORT) /* value forced by compiler command line, don't redefine */ #elif defined(_WIN32) # if defined(DBUS_STATIC_BUILD) # define DBUS_PRIVATE_EXPORT /* no decoration */ # elif defined(dbus_1_EXPORTS) # define DBUS_PRIVATE_EXPORT __declspec(dllexport) # else # define DBUS_PRIVATE_EXPORT __declspec(dllimport) # endif #elif defined(__GNUC__) && __GNUC__ >= 4 # define DBUS_PRIVATE_EXPORT __attribute__ ((__visibility__ ("default"))) #else # define DBUS_PRIVATE_EXPORT /* no decoration */ #endif /** @} */ #endif /* DBUS_MACROS_H */ dbus-1.10.6/dbus/dbus-errors.h0000644000175000017500000000550612602773110016120 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-errors.h Error reporting * * Copyright (C) 2002 Red Hat Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_ERROR_H #define DBUS_ERROR_H #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusErrors * @{ */ /** Mostly-opaque type representing an error that occurred */ typedef struct DBusError DBusError; /** * Object representing an exception. */ struct DBusError { const char *name; /**< public error name field */ const char *message; /**< public error message field */ unsigned int dummy1 : 1; /**< placeholder */ unsigned int dummy2 : 1; /**< placeholder */ unsigned int dummy3 : 1; /**< placeholder */ unsigned int dummy4 : 1; /**< placeholder */ unsigned int dummy5 : 1; /**< placeholder */ void *padding1; /**< placeholder */ }; #define DBUS_ERROR_INIT { NULL, NULL, TRUE, 0, 0, 0, 0, NULL } DBUS_EXPORT void dbus_error_init (DBusError *error); DBUS_EXPORT void dbus_error_free (DBusError *error); DBUS_EXPORT void dbus_set_error (DBusError *error, const char *name, const char *message, ...); DBUS_EXPORT void dbus_set_error_const (DBusError *error, const char *name, const char *message); DBUS_EXPORT void dbus_move_error (DBusError *src, DBusError *dest); DBUS_EXPORT dbus_bool_t dbus_error_has_name (const DBusError *error, const char *name); DBUS_EXPORT dbus_bool_t dbus_error_is_set (const DBusError *error); /** @} */ DBUS_END_DECLS #endif /* DBUS_ERROR_H */ dbus-1.10.6/dbus/dbus-connection.h0000644000175000017500000006265512602773110016753 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-connection.h DBusConnection object * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_CONNECTION_H #define DBUS_CONNECTION_H #include #include #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusConnection * @{ */ /* documented in dbus-watch.c */ typedef struct DBusWatch DBusWatch; /* documented in dbus-timeout.c */ typedef struct DBusTimeout DBusTimeout; /** Opaque type representing preallocated resources so a message can be sent without further memory allocation. */ typedef struct DBusPreallocatedSend DBusPreallocatedSend; /** Opaque type representing a method call that has not yet received a reply. */ typedef struct DBusPendingCall DBusPendingCall; /** Opaque type representing a connection to a remote application and associated incoming/outgoing message queues. */ typedef struct DBusConnection DBusConnection; /** Set of functions that must be implemented to handle messages sent to a particular object path. */ typedef struct DBusObjectPathVTable DBusObjectPathVTable; /** * Indicates the status of a #DBusWatch. */ typedef enum { DBUS_WATCH_READABLE = 1 << 0, /**< As in POLLIN */ DBUS_WATCH_WRITABLE = 1 << 1, /**< As in POLLOUT */ DBUS_WATCH_ERROR = 1 << 2, /**< As in POLLERR (can't watch for * this, but can be present in * current state passed to * dbus_watch_handle()). */ DBUS_WATCH_HANGUP = 1 << 3 /**< As in POLLHUP (can't watch for * it, but can be present in current * state passed to * dbus_watch_handle()). */ /* Internal to libdbus, there is also _DBUS_WATCH_NVAL in dbus-watch.h */ } DBusWatchFlags; /** * Indicates the status of incoming data on a #DBusConnection. This determines whether * dbus_connection_dispatch() needs to be called. */ typedef enum { DBUS_DISPATCH_DATA_REMAINS, /**< There is more data to potentially convert to messages. */ DBUS_DISPATCH_COMPLETE, /**< All currently available data has been processed. */ DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */ } DBusDispatchStatus; /** Called when libdbus needs a new watch to be monitored by the main * loop. Returns #FALSE if it lacks enough memory to add the * watch. Set by dbus_connection_set_watch_functions() or * dbus_server_set_watch_functions(). */ typedef dbus_bool_t (* DBusAddWatchFunction) (DBusWatch *watch, void *data); /** Called when dbus_watch_get_enabled() may return a different value * than it did before. Set by dbus_connection_set_watch_functions() * or dbus_server_set_watch_functions(). */ typedef void (* DBusWatchToggledFunction) (DBusWatch *watch, void *data); /** Called when libdbus no longer needs a watch to be monitored by the * main loop. Set by dbus_connection_set_watch_functions() or * dbus_server_set_watch_functions(). */ typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch, void *data); /** Called when libdbus needs a new timeout to be monitored by the main * loop. Returns #FALSE if it lacks enough memory to add the * watch. Set by dbus_connection_set_timeout_functions() or * dbus_server_set_timeout_functions(). */ typedef dbus_bool_t (* DBusAddTimeoutFunction) (DBusTimeout *timeout, void *data); /** Called when dbus_timeout_get_enabled() may return a different * value than it did before. * Set by dbus_connection_set_timeout_functions() or * dbus_server_set_timeout_functions(). */ typedef void (* DBusTimeoutToggledFunction) (DBusTimeout *timeout, void *data); /** Called when libdbus no longer needs a timeout to be monitored by the * main loop. Set by dbus_connection_set_timeout_functions() or * dbus_server_set_timeout_functions(). */ typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout, void *data); /** Called when the return value of dbus_connection_get_dispatch_status() * may have changed. Set with dbus_connection_set_dispatch_status_function(). */ typedef void (* DBusDispatchStatusFunction) (DBusConnection *connection, DBusDispatchStatus new_status, void *data); /** * Called when the main loop's thread should be notified that there's now work * to do. Set with dbus_connection_set_wakeup_main_function(). */ typedef void (* DBusWakeupMainFunction) (void *data); /** * Called during authentication to check whether the given UNIX user * ID is allowed to connect, if the client tried to auth as a UNIX * user ID. Normally on Windows this would never happen. Set with * dbus_connection_set_unix_user_function(). */ typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection, unsigned long uid, void *data); /** * Called during authentication to check whether the given Windows user * ID is allowed to connect, if the client tried to auth as a Windows * user ID. Normally on UNIX this would never happen. Set with * dbus_connection_set_windows_user_function(). */ typedef dbus_bool_t (* DBusAllowWindowsUserFunction) (DBusConnection *connection, const char *user_sid, void *data); /** * Called when a pending call now has a reply available. Set with * dbus_pending_call_set_notify(). */ typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, void *user_data); /** * Called when a message needs to be handled. The result indicates whether or * not more handlers should be run. Set with dbus_connection_add_filter(). */ typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection *connection, DBusMessage *message, void *user_data); DBUS_EXPORT DBusConnection* dbus_connection_open (const char *address, DBusError *error); DBUS_EXPORT DBusConnection* dbus_connection_open_private (const char *address, DBusError *error); DBUS_EXPORT DBusConnection* dbus_connection_ref (DBusConnection *connection); DBUS_EXPORT void dbus_connection_unref (DBusConnection *connection); DBUS_EXPORT void dbus_connection_close (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection *connection); DBUS_EXPORT char* dbus_connection_get_server_id (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_can_send_type (DBusConnection *connection, int type); DBUS_EXPORT void dbus_connection_set_exit_on_disconnect (DBusConnection *connection, dbus_bool_t exit_on_disconnect); DBUS_EXPORT void dbus_connection_flush (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection *connection, int timeout_milliseconds); DBUS_EXPORT dbus_bool_t dbus_connection_read_write (DBusConnection *connection, int timeout_milliseconds); DBUS_EXPORT DBusMessage* dbus_connection_borrow_message (DBusConnection *connection); DBUS_EXPORT void dbus_connection_return_message (DBusConnection *connection, DBusMessage *message); DBUS_EXPORT void dbus_connection_steal_borrowed_message (DBusConnection *connection, DBusMessage *message); DBUS_EXPORT DBusMessage* dbus_connection_pop_message (DBusConnection *connection); DBUS_EXPORT DBusDispatchStatus dbus_connection_get_dispatch_status (DBusConnection *connection); DBUS_EXPORT DBusDispatchStatus dbus_connection_dispatch (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_has_messages_to_send (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_send (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial); DBUS_EXPORT dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, DBusMessage *message, DBusPendingCall **pending_return, int timeout_milliseconds); DBUS_EXPORT DBusMessage * dbus_connection_send_with_reply_and_block (DBusConnection *connection, DBusMessage *message, int timeout_milliseconds, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_connection_set_watch_functions (DBusConnection *connection, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection *connection, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT void dbus_connection_set_wakeup_main_function (DBusConnection *connection, DBusWakeupMainFunction wakeup_main_function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT void dbus_connection_set_dispatch_status_function (DBusConnection *connection, DBusDispatchStatusFunction function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_connection_get_unix_user (DBusConnection *connection, unsigned long *uid); DBUS_EXPORT dbus_bool_t dbus_connection_get_unix_process_id (DBusConnection *connection, unsigned long *pid); DBUS_EXPORT dbus_bool_t dbus_connection_get_adt_audit_session_data (DBusConnection *connection, void **data, dbus_int32_t *data_size); DBUS_EXPORT void dbus_connection_set_unix_user_function (DBusConnection *connection, DBusAllowUnixUserFunction function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_connection_get_windows_user (DBusConnection *connection, char **windows_sid_p); DBUS_EXPORT void dbus_connection_set_windows_user_function (DBusConnection *connection, DBusAllowWindowsUserFunction function, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT void dbus_connection_set_allow_anonymous (DBusConnection *connection, dbus_bool_t value); DBUS_EXPORT void dbus_connection_set_route_peer_messages (DBusConnection *connection, dbus_bool_t value); /* Filters */ DBUS_EXPORT dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, DBusHandleMessageFunction function, void *user_data, DBusFreeFunction free_data_function); DBUS_EXPORT void dbus_connection_remove_filter (DBusConnection *connection, DBusHandleMessageFunction function, void *user_data); /* Other */ DBUS_EXPORT dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT void dbus_connection_free_data_slot (dbus_int32_t *slot_p); DBUS_EXPORT dbus_bool_t dbus_connection_set_data (DBusConnection *connection, dbus_int32_t slot, void *data, DBusFreeFunction free_data_func); DBUS_EXPORT void* dbus_connection_get_data (DBusConnection *connection, dbus_int32_t slot); DBUS_EXPORT void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe); DBUS_EXPORT void dbus_connection_set_max_message_size (DBusConnection *connection, long size); DBUS_EXPORT long dbus_connection_get_max_message_size (DBusConnection *connection); DBUS_EXPORT void dbus_connection_set_max_received_size (DBusConnection *connection, long size); DBUS_EXPORT long dbus_connection_get_max_received_size (DBusConnection *connection); DBUS_EXPORT void dbus_connection_set_max_message_unix_fds (DBusConnection *connection, long n); DBUS_EXPORT long dbus_connection_get_max_message_unix_fds (DBusConnection *connection); DBUS_EXPORT void dbus_connection_set_max_received_unix_fds(DBusConnection *connection, long n); DBUS_EXPORT long dbus_connection_get_max_received_unix_fds(DBusConnection *connection); DBUS_EXPORT long dbus_connection_get_outgoing_size (DBusConnection *connection); DBUS_EXPORT long dbus_connection_get_outgoing_unix_fds (DBusConnection *connection); DBUS_EXPORT DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection *connection); DBUS_EXPORT void dbus_connection_free_preallocated_send (DBusConnection *connection, DBusPreallocatedSend *preallocated); DBUS_EXPORT void dbus_connection_send_preallocated (DBusConnection *connection, DBusPreallocatedSend *preallocated, DBusMessage *message, dbus_uint32_t *client_serial); /* Object tree functionality */ /** * Called when a #DBusObjectPathVTable is unregistered (or its connection is freed). * Found in #DBusObjectPathVTable. */ typedef void (* DBusObjectPathUnregisterFunction) (DBusConnection *connection, void *user_data); /** * Called when a message is sent to a registered object path. Found in * #DBusObjectPathVTable which is registered with dbus_connection_register_object_path() * or dbus_connection_register_fallback(). */ typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection *connection, DBusMessage *message, void *user_data); /** * Virtual table that must be implemented to handle a portion of the * object path hierarchy. Attach the vtable to a particular path using * dbus_connection_register_object_path() or * dbus_connection_register_fallback(). */ struct DBusObjectPathVTable { DBusObjectPathUnregisterFunction unregister_function; /**< Function to unregister this handler */ DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ void (* dbus_internal_pad1) (void *); /**< Reserved for future expansion */ void (* dbus_internal_pad2) (void *); /**< Reserved for future expansion */ void (* dbus_internal_pad3) (void *); /**< Reserved for future expansion */ void (* dbus_internal_pad4) (void *); /**< Reserved for future expansion */ }; DBUS_EXPORT dbus_bool_t dbus_connection_try_register_object_path (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data); DBUS_EXPORT dbus_bool_t dbus_connection_try_register_fallback (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection, const char *path, const DBusObjectPathVTable *vtable, void *user_data); DBUS_EXPORT dbus_bool_t dbus_connection_unregister_object_path (DBusConnection *connection, const char *path); DBUS_EXPORT dbus_bool_t dbus_connection_get_object_path_data (DBusConnection *connection, const char *path, void **data_p); DBUS_EXPORT dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, const char *parent_path, char ***child_entries); DBUS_EXPORT dbus_bool_t dbus_connection_get_unix_fd (DBusConnection *connection, int *fd); DBUS_EXPORT dbus_bool_t dbus_connection_get_socket (DBusConnection *connection, int *fd); /** @} */ /** * @addtogroup DBusWatch * @{ */ #ifndef DBUS_DISABLE_DEPRECATED DBUS_EXPORT DBUS_DEPRECATED int dbus_watch_get_fd (DBusWatch *watch); #endif DBUS_EXPORT int dbus_watch_get_unix_fd (DBusWatch *watch); DBUS_EXPORT int dbus_watch_get_socket (DBusWatch *watch); DBUS_EXPORT unsigned int dbus_watch_get_flags (DBusWatch *watch); DBUS_EXPORT void* dbus_watch_get_data (DBusWatch *watch); DBUS_EXPORT void dbus_watch_set_data (DBusWatch *watch, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_watch_handle (DBusWatch *watch, unsigned int flags); DBUS_EXPORT dbus_bool_t dbus_watch_get_enabled (DBusWatch *watch); /** @} */ /** * @addtogroup DBusTimeout * @{ */ DBUS_EXPORT int dbus_timeout_get_interval (DBusTimeout *timeout); DBUS_EXPORT void* dbus_timeout_get_data (DBusTimeout *timeout); DBUS_EXPORT void dbus_timeout_set_data (DBusTimeout *timeout, void *data, DBusFreeFunction free_data_function); DBUS_EXPORT dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout); DBUS_EXPORT dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout); /** @} */ DBUS_END_DECLS #endif /* DBUS_CONNECTION_H */ dbus-1.10.6/dbus/dbus-bus.h0000644000175000017500000000662012602773110015373 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-bus.h Convenience functions for communicating with the bus. * * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_BUS_H #define DBUS_BUS_H #include DBUS_BEGIN_DECLS /** * @addtogroup DBusBus * @{ */ DBUS_EXPORT DBusConnection *dbus_bus_get (DBusBusType type, DBusError *error); DBUS_EXPORT DBusConnection *dbus_bus_get_private (DBusBusType type, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_bus_register (DBusConnection *connection, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_bus_set_unique_name (DBusConnection *connection, const char *unique_name); DBUS_EXPORT const char* dbus_bus_get_unique_name (DBusConnection *connection); DBUS_EXPORT unsigned long dbus_bus_get_unix_user (DBusConnection *connection, const char *name, DBusError *error); DBUS_EXPORT char* dbus_bus_get_id (DBusConnection *connection, DBusError *error); DBUS_EXPORT int dbus_bus_request_name (DBusConnection *connection, const char *name, unsigned int flags, DBusError *error); DBUS_EXPORT int dbus_bus_release_name (DBusConnection *connection, const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_bus_name_has_owner (DBusConnection *connection, const char *name, DBusError *error); DBUS_EXPORT dbus_bool_t dbus_bus_start_service_by_name (DBusConnection *connection, const char *name, dbus_uint32_t flags, dbus_uint32_t *reply, DBusError *error); DBUS_EXPORT void dbus_bus_add_match (DBusConnection *connection, const char *rule, DBusError *error); DBUS_EXPORT void dbus_bus_remove_match (DBusConnection *connection, const char *rule, DBusError *error); /** @} */ DBUS_END_DECLS #endif /* DBUS_BUS_H */ dbus-1.10.6/dbus/dbus-address.h0000644000175000017500000000412712602773110016227 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-address.h Server address parser. * * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef DBUS_ADDRESS_H #define DBUS_ADDRESS_H #include #include DBUS_BEGIN_DECLS /** * @addtogroup DBusAddress * @{ */ /** Opaque type representing one of the semicolon-separated items in an address */ typedef struct DBusAddressEntry DBusAddressEntry; DBUS_EXPORT dbus_bool_t dbus_parse_address (const char *address, DBusAddressEntry ***entry, int *array_len, DBusError *error); DBUS_EXPORT const char *dbus_address_entry_get_value (DBusAddressEntry *entry, const char *key); DBUS_EXPORT const char *dbus_address_entry_get_method (DBusAddressEntry *entry); DBUS_EXPORT void dbus_address_entries_free (DBusAddressEntry **entries); DBUS_EXPORT char* dbus_address_escape_value (const char *value); DBUS_EXPORT char* dbus_address_unescape_value (const char *value, DBusError *error); /** @} */ DBUS_END_DECLS #endif /* DBUS_ADDRESS_H */ dbus-1.10.6/dbus/dbus.h0000644000175000017500000000756312602773110014613 0ustar00smcvsmcv00000000000000/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus.h Convenience header including all other headers * * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DBUS_H #define DBUS_H #define DBUS_INSIDE_DBUS_H 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DBUS_INSIDE_DBUS_H /** * @defgroup DBus D-Bus low-level public API * @brief The low-level public API of the D-Bus library * * libdbus provides a low-level C API intended primarily for use by * bindings to specific object systems and languages. D-Bus is most * convenient when used with the GLib bindings, Python bindings, Qt * bindings, Mono bindings, and so forth. This low-level API has a * lot of complexity useful only for bindings. * * @{ */ /** @} */ /** * @mainpage * * This manual documents the low-level D-Bus C API. If you use * this low-level API directly, you're signing up for some pain. * * Caveats aside, you might get started learning the low-level API by reading * about @ref DBusConnection and @ref DBusMessage. * * There are several other places to look for D-Bus information, such * as the tutorial and the specification; those can be found at the D-Bus * website. If you're interested in a sysadmin or package * maintainer's perspective on the dbus-daemon itself and its * configuration, be sure to check out the man pages as well. * * The low-level API documented in this manual deliberately lacks * most convenience functions - those are left up to higher-level libraries * based on frameworks such as GLib, Qt, Python, Mono, Java, * etc. These higher-level libraries (often called "D-Bus bindings") * have features such as object systems and main loops that allow a * much more convenient API. * * The low-level API also contains plenty of clutter to support * integration with arbitrary object systems, languages, main loops, * and so forth. These features add a lot of noise to the API that you * probably don't care about unless you're coding a binding. * * This manual also contains docs for @ref DBusInternals "D-Bus internals", * so you can use it to get oriented to the D-Bus source code if you're * interested in patching the code. You should also read the * file HACKING which comes with the source code if you plan to contribute to * D-Bus. * * As you read the code, you can identify internal D-Bus functions * because they start with an underscore ('_') character. Also, any * identifier or macro that lacks a DBus, dbus_, or DBUS_ namepace * prefix is internal, with a couple of exceptions such as #NULL, * #TRUE, and #FALSE. */ #endif /* DBUS_H */ dbus-1.10.6/dbus/Makefile.am0000644000175000017500000001637412602773110015541 0ustar00smcvsmcv00000000000000 dbusdatadir=$(datadir)/dbus-1 AM_CPPFLAGS = \ -I$(top_builddir) \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ $(SYSTEMD_CFLAGS) \ $(VALGRIND_CFLAGS) \ -DDBUS_COMPILATION \ -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \ -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \ -DDBUS_SESSION_CONFIG_FILE=\""$(dbusdatadir)/session.conf"\" \ $(NULL) AM_CFLAGS = if HAVE_VISIBILITY if !DBUS_WIN AM_CFLAGS += $(CFLAG_VISIBILITY) AM_CPPFLAGS += \ -DDBUS_EXPORT='__attribute__((__visibility__("default")))' \ -DDBUS_PRIVATE_EXPORT='__attribute__((__visibility__("default")))' \ $(NULL) endif endif # if assertions are enabled, improve backtraces AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ dbusincludedir=$(includedir)/dbus-1.0/dbus dbusarchincludedir=$(libdir)/dbus-1.0/include/dbus lib_LTLIBRARIES=libdbus-1.la # # Deal with W32 .def and version-info.rc stuff # if DBUS_WIN SUFFIXES = rc .rc.o: $(WINDRES) $< -o $@ dbus_res = versioninfo.o dbus_res_ldflag = -Wl,$(dbus_res) no_undefined = -no-undefined export_symbols = EXTRA_libdbus_1_la_DEPENDENCIES = $(dbus_res) intllibs = else dbus_res = dbus_res_ldflag = no_undefined = intllibs = @LTLIBINTL@ endif # # Platform-dependent sources: # if DBUS_WIN DBUS_LIB_arch_sources = \ dbus-server-win.c \ dbus-server-win.h if DBUS_WINCE wince_source = dbus-sysdeps-wince-glue.h dbus-sysdeps-wince-glue.c else wince_source = endif DBUS_SHARED_arch_sources = \ $(wince_source) \ dbus-file-win.c \ dbus-pipe-win.c \ dbus-sockets-win.h \ dbus-sysdeps-win.c \ dbus-sysdeps-win.h \ dbus-sysdeps-thread-win.c \ dbus-transport-win.c \ dbus-transport-win.h DBUS_UTIL_arch_sources = \ dbus-sysdeps-util-win.c \ dbus-spawn-win.c else if DBUS_ENABLE_LAUNCHD launchd_source = dbus-server-launchd.h dbus-server-launchd.c else launchd_source = endif DBUS_LIB_arch_sources = \ dbus-uuidgen.c \ dbus-uuidgen.h \ dbus-server-unix.c \ dbus-server-unix.h DBUS_SHARED_arch_sources = \ $(launchd_source) \ dbus-file-unix.c \ dbus-pipe-unix.c \ dbus-sysdeps-unix.c \ dbus-sysdeps-unix.h \ dbus-sysdeps-pthread.c \ dbus-transport-unix.c \ dbus-transport-unix.h \ dbus-userdb.c \ dbus-userdb.h \ $(NULL) DBUS_UTIL_arch_sources = \ dbus-sysdeps-util-unix.c \ dbus-userdb-util.c \ dbus-spawn.c endif if HAVE_LINUX_EPOLL DBUS_UTIL_arch_sources += dbus-socket-set-epoll.c endif dbusinclude_HEADERS= \ dbus.h \ dbus-address.h \ dbus-bus.h \ dbus-connection.h \ dbus-errors.h \ dbus-macros.h \ dbus-memory.h \ dbus-message.h \ dbus-misc.h \ dbus-pending-call.h \ dbus-protocol.h \ dbus-server.h \ dbus-shared.h \ dbus-signature.h \ dbus-syntax.h \ dbus-threads.h \ dbus-types.h nodist_dbusarchinclude_HEADERS= \ dbus-arch-deps.h ### source code that goes in the installed client library ### and is specific to library functionality DBUS_LIB_SOURCES= \ dbus-address.c \ dbus-auth.c \ dbus-auth.h \ dbus-bus.c \ dbus-connection.c \ dbus-connection-internal.h \ dbus-credentials.c \ dbus-credentials.h \ dbus-errors.c \ dbus-keyring.c \ dbus-keyring.h \ dbus-marshal-header.c \ dbus-marshal-header.h \ dbus-marshal-byteswap.c \ dbus-marshal-byteswap.h \ dbus-marshal-recursive.c \ dbus-marshal-recursive.h \ dbus-marshal-validate.c \ dbus-marshal-validate.h \ dbus-message.c \ dbus-message-internal.h \ dbus-message-private.h \ dbus-misc.c \ dbus-nonce.h \ dbus-nonce.c \ dbus-object-tree.c \ dbus-object-tree.h \ dbus-pending-call.c \ dbus-pending-call-internal.h \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ dbus-server-debug-pipe.c \ dbus-server-debug-pipe.h \ dbus-server-protected.h \ dbus-server-socket.c \ dbus-server-socket.h \ $(DBUS_LIB_arch_sources) \ dbus-sha.c \ dbus-sha.h \ dbus-signature.c \ dbus-syntax.c \ dbus-timeout.c \ dbus-timeout.h \ dbus-threads-internal.h \ dbus-threads.c \ dbus-transport.c \ dbus-transport.h \ dbus-transport-protected.h \ dbus-transport-socket.c \ dbus-transport-socket.h \ dbus-watch.c \ dbus-watch.h ### source code that goes in the installed client library ### AND is generic utility functionality used by the ### daemon or test programs (all symbols in here should ### be underscore-prefixed) DBUS_SHARED_SOURCES= \ dbus-dataslot.c \ dbus-dataslot.h \ dbus-file.c \ dbus-file.h \ dbus-hash.c \ dbus-hash.h \ dbus-internals.c \ dbus-internals.h \ dbus-list.c \ dbus-list.h \ dbus-marshal-basic.c \ dbus-marshal-basic.h \ dbus-memory.c \ dbus-mempool.c \ dbus-mempool.h \ dbus-pipe.c \ dbus-pipe.h \ dbus-string.c \ dbus-string.h \ dbus-string-private.h \ $(DBUS_SHARED_arch_sources) \ dbus-sysdeps.c \ dbus-sysdeps.h \ dbus-valgrind-internal.h ### source code that is generic utility functionality used ### by the bus daemon or test apps, but is NOT included ### in the D-Bus client library (all symbols in here ### should be underscore-prefixed but don't really need ### to be unless they move to DBUS_SHARED_SOURCES later) DBUS_UTIL_SOURCES= \ dbus-asv-util.c \ dbus-asv-util.h \ dbus-auth-script.c \ dbus-auth-script.h \ dbus-auth-util.c \ dbus-credentials-util.c \ dbus-mainloop.c \ dbus-mainloop.h \ dbus-marshal-byteswap-util.c \ dbus-marshal-recursive-util.c \ dbus-marshal-validate-util.c \ dbus-message-factory.c \ dbus-message-factory.h \ dbus-message-util.c \ dbus-shell.c \ dbus-shell.h \ $(DBUS_UTIL_arch_sources) \ dbus-socket-set.h \ dbus-socket-set.c \ dbus-socket-set-poll.c \ dbus-spawn.h \ dbus-string-util.c \ dbus-sysdeps-util.c \ dbus-test.c \ dbus-test.h libdbus_1_la_SOURCES= \ $(DBUS_LIB_SOURCES) \ $(DBUS_SHARED_SOURCES) libdbus_internal_la_SOURCES= \ $(DBUS_UTIL_SOURCES) BUILT_SOURCES=$(nodist_dbusarchinclude_HEADERS) EXTRA_DIST=dbus-arch-deps.h.in noinst_LTLIBRARIES=libdbus-internal.la libdbus_1_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -Ddbus_1_EXPORTS \ $(NULL) if HAVE_LD_VERSION_SCRIPT SYMBOL_EXPORT_LDFLAGS=-Wl,--version-script=Version else SYMBOL_EXPORT_LDFLAGS= endif libdbus_1_la_LIBADD= $(LIBDBUS_LIBS) libdbus_1_la_LDFLAGS = \ $(AM_LDFLAGS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ $(SYMBOL_EXPORT_LDFLAGS) \ -no-undefined \ $(NULL) libdbus_internal_la_LIBADD=$(LIBDBUS_LIBS) libdbus-1.la if DBUS_WIN # This must be a separate convenience library, otherwise libtool notices # that libdbus-1 might contain C++, links it with g++ and links in libstdc++, # even on Unix where in fact it doesn't contain any C++. For Windows, where # this code is used, we don't actually need libstdc++. noinst_LTLIBRARIES += libdbus-init-win.la libdbus_init_win_la_SOURCES = dbus-init-win.cpp libdbus_1_la_LIBADD += libdbus-init-win.la endif noinst_PROGRAMS = if DBUS_ENABLE_EMBEDDED_TESTS # We can't actually run this til we've reached test/ noinst_PROGRAMS += test-dbus endif test_dbus_SOURCES= \ dbus-test-main.c test_dbus_LDADD = libdbus-internal.la ## mop up the gcov files clean-local: /bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true dbus-1.10.6/cmake/0000755000175000017500000000000012627362053013624 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/CMakeLists.txt0000644000175000017500000006035512624705346016400 0ustar00smcvsmcv00000000000000# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/modules") # we do not need to have WIN32 defined set(CMAKE_LEGACY_CYGWIN_WIN32 0) project(dbus) # we need to be up to date CMAKE_MINIMUM_REQUIRED(VERSION 2.4.4 FATAL_ERROR) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) if(CMAKE_MAJOR_VERSION GREATER 2) cmake_policy(SET CMP0026 NEW) if (CMAKE_MAJOR_VERSION GREATER 4 OR CMAKE_MINOR_VERSION GREATER 1) cmake_policy(SET CMP0053 NEW) cmake_policy(SET CMP0054 NEW) endif() endif() # detect version include(MacrosAutotools) autoinit(../configure.ac) autoversion(dbus) if(EXISTS ../config.h.in) autoheaderchecks(../config.h.in ConfigureChecks.cmake config.h.cmake) else() message(STATUS "Generate config.h.in with autogen.sh to enable cmake header difference check.") endif() # used by file version info set (DBUS_PATCH_VERSION "0") # set PACKAGE_... variables autopackage( dbus ${DBUS_VERSION_STRING} "http://dbus.freedesktop.org" "https://bugs.freedesktop.org/enter_bug.cgi?product=dbus" ) include(Macros) TIMESTAMP(DBUS_BUILD_TIMESTAMP) ########### basic vars ############### if (DBUSDIR) set(DBUS_INSTALL_DIR "${DBUSDIR}") endif (DBUSDIR) if ($ENV{DBUSDIR}) set(DBUS_INSTALL_DIR "$ENV{DBUSDIR}") endif ($ENV{DBUSDIR}) if (DBUS_INSTALL_DIR) set(CMAKE_INSTALL_PREFIX "${DBUS_INSTALL_DIR}" CACHE PATH "install prefix" FORCE) else (DBUS_INSTALL_DIR) set(DBUS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}") endif (DBUS_INSTALL_DIR) # autotools style if (NOT DATAROOTDIR) set (DATAROOTDIR share) endif() if (NOT DATADIR) set (DATADIR ${DATAROOTDIR}) endif() if (NOT DOCDIR) SET(DOCDIR ${DATAROOTDIR}/doc/dbus) endif() if (NOT DBUS_DATADIR) SET(DBUS_DATADIR ${DATADIR}) endif() set(DBUS_PREFIX ${DBUS_INSTALL_DIR}) set(prefix ${DBUS_INSTALL_DIR}) set(exec_prefix ${prefix}) set(EXPANDED_LIBDIR ${DBUS_INSTALL_DIR}/lib) set(EXPANDED_INCLUDEDIR ${DBUS_INSTALL_DIR}/include) set(EXPANDED_BINDIR ${DBUS_INSTALL_DIR}/bin) set(EXPANDED_SYSCONFDIR ${DBUS_INSTALL_DIR}/etc) set(EXPANDED_LOCALSTATEDIR ${DBUS_INSTALL_DIR}/var) set(EXPANDED_DATADIR ${DBUS_INSTALL_DIR}/${DBUS_DATADIR}) set(DBUS_MACHINE_UUID_FILE ${DBUS_INSTALL_DIR}/lib/dbus/machine-id) set(DBUS_BINDIR ${EXPANDED_BINDIR}) set(DBUS_DAEMONDIR ${EXPANDED_BINDIR}) set(DBUS_LOCALSTATEDIR ${EXPANDED_LOCALSTATEDIR}) # On Windows this is relative to where we put the bus setup, in # ${datadir}/dbus-1. For simplicity, we only do this if # ${sysconfdir} = ${prefix}/etc and ${datadir} = ${prefix}/share. # # On Unix, or on Windows with weird install layouts, it's the absolute path. if(WIN32 AND ${EXPANDED_SYSCONFDIR} STREQUAL ${prefix}/etc AND ${EXPANDED_DATADIR} STREQUAL ${prefix}/share) set(SYSCONFDIR_FROM_PKGDATADIR ../../etc) set(DATADIR_FROM_PKGSYSCONFDIR ../../share) else() set(SYSCONFDIR_FROM_PKGDATADIR ${EXPANDED_SYSCONFDIR}) set(DATADIR_FROM_PKGSYSCONFDIR ${EXPANDED_DATADIR}) endif() set(DBUS_LIBEXECDIR ${EXPANDED_LIBDIR}) set(DBUS_DATADIR ${EXPANDED_DATADIR}) #enable building of shared library SET(BUILD_SHARED_LIBS ON) if(WIN32) set(INSTALL_TARGETS_DEFAULT_ARGS RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") else() set(INSTALL_TARGETS_DEFAULT_ARGS RUNTIME DESTINATION "${EXPANDED_LIBDIR}" LIBRARY DESTINATION "${EXPANDED_LIBDIR}" ARCHIVE DESTINATION "${EXPANDED_LIBDIR}") endif() if (CYGWIN) set (WIN32) endif (CYGWIN) # search for required packages if (WIN32) # include local header first to avoid using old installed header set (CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} ${CMAKE_SOURCE_DIR}/..) find_package(LibIconv) include(Win32Macros) addExplorerWrapper(${CMAKE_PROJECT_NAME}) endif (WIN32) if(NOT WIN32) option (DBUS_ENABLE_ABSTRACT_SOCKETS "enable support for abstract sockets" ON) set (CMAKE_THREAD_PREFER_PTHREAD ON) include (FindThreads) endif(NOT WIN32) option (DBUS_DISABLE_ASSERT "Disable assertion checking" OFF) option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF) if(WIN32) set(FD_SETSIZE "8192" CACHE STRING "The maximum number of connections that can be handled at once") endif() find_package(EXPAT) find_package(X11) find_package(GLib2) find_package(GObject) if(GLIB2_FOUND AND GOBJECT_FOUND) option (DBUS_WITH_GLIB "build with glib" ON) endif() # analogous to AC_USE_SYSTEM_EXTENSIONS in configure.ac add_definitions(-D_GNU_SOURCE) # do config checks INCLUDE(ConfigureChecks.cmake) # @TODO: how to remove last dir from ${CMAKE_SOURCE_DIR} ? SET(DBUS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/..) # make some more macros available include (MacroLibrary) if(VCS) set(DBUS_VERBOSE_C_S 1 CACHE STRING "verbose mode" FORCE) endif(VCS) if(WIN32) if(MSVC) # controll folders in msvc projects include(ProjectSourceGroup) if(NOT GROUP_CODE) #set(GROUP_CODE split) #cmake default set(GROUP_CODE flat) endif(NOT GROUP_CODE) ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) # Use the highest warning level if (WALL) set(WALL 1 CACHE STRING "all warnings" FORCE) set(CMAKE_CXX_WARNING_LEVEL 4 CACHE STRING "warning level" FORCE) if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") STRING(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") endif(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") if(CMAKE_C_FLAGS MATCHES "/W[0-4]") STRING(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") else(CMAKE_C_FLAGS MATCHES "/W[0-4]") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") endif(CMAKE_C_FLAGS MATCHES "/W[0-4]") else (WALL) set(CMAKE_CXX_WARNING_LEVEL 3 CACHE STRING "warning level" FORCE) endif (WALL) SET(MSVC_W_ERROR " /we4028 /we4013 /we4133 /we4047 /we4031 /we4002 /we4003 /we4114") SET(MSVC_W_DISABLE " /wd4127 /wd4090 /wd4101 /wd4244") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /FIconfig.h ${MSVC_W_ERROR} ${MSVC_W_DISABLE}") SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /FIconfig.h ${MSVC_W_ERROR} ${MSVC_W_DISABLE}") endif(MSVC) endif(WIN32) if (UNIX AND NOT DBUS_DISABLE_ASSERT) # required for backtrace SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wl,--export-dynamic") SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wl,--export-dynamic") add_definitions(-DDBUS_BUILT_R_DYNAMIC) endif (UNIX AND NOT DBUS_DISABLE_ASSERT) if(DBUS_WITH_GLIB) autodefine(GLIB_VERSION_MIN_REQUIRED) autodefine(GLIB_VERSION_MAX_ALLOWED) endif() SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") if(MSVC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /w14018") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /w14018") else() SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare") endif() ######################################################################### # Windows CE (>= 5.0.0) # # WinCE support now relies on the presence of platform files, found in cmake/modules/platform # Cmake 2.8.0 doesn't include WinCE platform files by default, but working ones can be found # on CMake's bugtracker : # http://public.kitware.com/Bug/view.php?id=7919 # # for cmake 2.8.0 get the following patch only : # http://public.kitware.com/Bug/file_download.php?file_id=2944&type=bug # # after applying the patch, you can enable the WinCE build by specifying : # cmake [...] -DCMAKE_SYSTEM_NAME=WinCE -DCMAKE_SYSTEM_VERSION=X.XX # (where X.XX is your actual WinCE version, e.g. 5.02 for Windows Mobile 6) # # Note that you should have a proper cross-compilation environment set up prior to running # cmake, ie. the PATH, INCLUDE and LIB env vars pointing to your CE SDK/toolchain. # if(WINCE) MESSAGE("Building for WinCE (${CMAKE_SYSTEM_VERSION})") endif(WINCE) ######################################################################### ENABLE_TESTING() ######################################################################### # Disallow in-source build #macro_ensure_out_of_source_build("dbus requires an out of source build. Please create a separate build directory and run 'cmake path_to_dbus [options]' there.") # ... and warn in case of an earlier in-source build #set(generatedFileInSourceDir EXISTS ${dbus_SOURCE_DIR}/config.h) #if(${generatedFileInSourceDir}) # message(STATUS "config.h exists in your source directory.") #endif(${generatedFileInSourceDir}) ######################################################################### if (WIN32 OR CYGWIN) set (LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) else (WIN32 OR CYGWIN) set (LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) endif (WIN32 OR CYGWIN) set (EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) # for including config.h and for includes like include_directories( ${CMAKE_SOURCE_DIR}/.. ${CMAKE_BINARY_DIR} ${CMAKE_INCLUDE_PATH} ) # linker search directories link_directories(${DBUS_LIB_DIR} ${LIBRARY_OUTPUT_PATH} ) include_directories( ${CMAKE_LIBRARY_PATH} ) set(DBUS_INCLUDES) ENABLE_TESTING() ########### command line options ############### # TODO: take check from configure.in option (DBUS_BUILD_TESTS "enable unit test code" ON) if(DBUS_BUILD_TESTS) set (DBUS_ENABLE_EMBEDDED_TESTS ON) set (DBUS_ENABLE_MODULAR_TESTS ON) add_definitions(-DDBUS_ENABLE_EMBEDDED_TESTS -DDBUS_ENABLE_MODULAR_TESTS) endif(DBUS_BUILD_TESTS) option (DBUS_USE_OUTPUT_DEBUG_STRING "enable win32 debug port for message output" OFF) if(DBUS_USE_OUTPUT_DEBUG_STRING) add_definitions(-DDBUS_USE_OUTPUT_DEBUG_STRING) endif(DBUS_USE_OUTPUT_DEBUG_STRING) if(WIN32) # win32 dbus service support - this support is not complete option (DBUS_SERVICE "enable dbus service installer" OFF) endif(WIN32) option (DBUS_ENABLE_ANSI "enable -ansi -pedantic gcc flags" OFF) if(DBUS_ENABLE_ANSI) if(NOT MSVC) add_definitions(-ansi -D_POSIX_C_SOURCE=199309L -D_BSD_SOURCE -pedantic) else(NOT MSVC) add_definitions(-Za -D_POSIX_C_SOURCE=199309L -D_BSD_SOURCE -W4) endif(NOT MSVC) endif(DBUS_ENABLE_ANSI) option (DBUS_ENABLE_VERBOSE_MODE "support verbose debug mode" ON) option (DBUS_DISABLE_CHECKS "Disable public API sanity checking" OFF) if(NOT MSVC) option (DBUS_GCOV_ENABLED "compile with coverage profiling instrumentation (gcc only)" OFF) if(DBUS_GCOV_ENABLED) add_definitions(-fprofile-arcs -ftest-coverage) # FIXME!!!! ## remove optimization # CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'` endif(DBUS_GCOV_ENABLED) endif(NOT MSVC) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") option (DBUS_BUS_ENABLE_INOTIFY "build with inotify support (linux only)" ON) if(DBUS_BUS_ENABLE_INOTIFY) if(NOT HAVE_SYS_INOTIFY_H) message(FATAL_ERROR "sys/inotify.h not found!") endif(NOT HAVE_SYS_INOTIFY_H) endif(DBUS_BUS_ENABLE_INOTIFY) elseif("${CMAKE_SYSTEM_NAME}" MATCHES ".*BSD") option (DBUS_BUS_ENABLE_KQUEUE "build with kqueue support (FreeBSD only)" ON) if(DBUS_BUS_ENABLE_KQUEUE) if(NOT HAVE_SYS_EVENT_H) message(FATAL_ERROR "sys/event.h not found!") endif(NOT HAVE_SYS_EVENT_H) endif(DBUS_BUS_ENABLE_KQUEUE) endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") STRING(TOUPPER ${CMAKE_SYSTEM_NAME} sysname) if("${sysname}" MATCHES ".*SOLARIS.*") option (HAVE_CONSOLE_OWNER_FILE "enable console owner file (solaris only)" ON) if(HAVE_CONSOLE_OWNER_FILE) set (DBUS_CONSOLE_OWNER_FILE "/dev/console" CACHE STRING "Directory to check for console ownerhip") endif(HAVE_CONSOLE_OWNER_FILE) endif("${sysname}" MATCHES ".*SOLARIS.*") if(NOT EXPAT_FOUND) message(FATAL_ERROR "expat not found!") endif(NOT EXPAT_FOUND) SET(XML_LIB "Expat") SET(XML_LIBRARY ${EXPAT_LIBRARIES}) SET(XML_INCLUDE_DIR ${EXPAT_INCLUDE_DIR}) # all missing or hardcoded for now # 'hidden' ones set(atomic_int OFF) set(atomic_int486 OFF) if(CMAKE_COMPILER_IS_GNUCC AND NOT DBUS_ENABLE_ANSI) FIND_PROGRAM(UNAME_EXECUTABLE NAMES uname PATHS /bin /usr/bin /usr/local/bin c:/Programme/MSys/bin d:/Programme/MSys/bin) if(UNAME_EXECUTABLE) EXECUTE_PROCESS(COMMAND ${UNAME_EXECUTABLE} "-m" OUTPUT_VARIABLE UNAME_OUTPUT) if("UNAME_OUTPUT" MATCHES "^.*i[0123]86.*$") set(atomic_int ON) else("UNAME_OUTPUT" MATCHES "^.*i[0123]86.*$") if("UNAME_OUTPUT" MATCHES "^.*i?86.*$") set(atomic_int ON) set(atomic_int_486 ON) endif("UNAME_OUTPUT" MATCHES "^.*i?86.*$") endif("UNAME_OUTPUT" MATCHES "^.*i[0123]86.*$") endif(UNAME_EXECUTABLE) endif(CMAKE_COMPILER_IS_GNUCC AND NOT DBUS_ENABLE_ANSI) set (DBUS_HAVE_ATOMIC_INT ${atomic_int} CACHE STRING "Some atomic integer implementation present") set (DBUS_USE_ATOMIC_INT_486 ${atomic_int_486} CACHE STRING "Use atomic integer implementation for 486") if(X11_FOUND) option (DBUS_BUILD_X11 "Build with X11 autolaunch support " ON) endif(X11_FOUND) # test binary names if (WIN32) # follow Automake's naming convention so we can share .in files set (EXEEXT ${CMAKE_EXECUTABLE_SUFFIX}) endif(WIN32) if (MSVC_IDE) if(CMAKE_BUILD_TYPE MATCHES Debug) set(IDE_BIN /Debug ) message(STATUS) message(STATUS "Visual Studio: test programs will only work with 'Debug' configuration!") message(STATUS "To run tests with 'Release' configuration use -DCMAKE_BUILD_TYPE=Release") message(STATUS "Add '..\\..\\test\\data' to the command line option of the test programs") message(STATUS) else(CMAKE_BUILD_TYPE MATCHES Debug) set(IDE_BIN /Release) message(STATUS) message(STATUS "Visual Studio: test programs will only work with 'Release' configuration!") message(STATUS "To run tests with 'Debug' configuration use -DCMAKE_BUILD_TYPE=Debug") message(STATUS "Add '..\\..\\test\\data' to the command line option of the test programs") message(STATUS) endif(CMAKE_BUILD_TYPE MATCHES Debug) set (TEST_PATH_FORCE FORCE) FILE(REMOVE ${CMAKE_BINARY_DIR}/data/dbus-1/services) endif (MSVC_IDE) #### Find socket directories if (NOT $ENV{TMPDIR} STREQUAL "") set (DBUS_SESSION_SOCKET_DIR $ENV{TMPDIR}) else (NOT $ENV{TMPDIR} STREQUAL "") if (NOT $ENV{TEMP} STREQUAL "") set (DBUS_SESSION_SOCKET_DIR $ENV{TEMP}) else (NOT $ENV{TEMP} STREQUAL "") if (NOT $ENV{TMP} STREQUAL "") set (DBUS_SESSION_SOCKET_DIR $ENV{TMP}) else (NOT $ENV{TMP} STREQUAL "") if (WIN32) #Should never happen, both TMP and TEMP seem always set on Windows message(FATAL_ERROR "Could not determine a usable temporary directory") else(WIN32) set (DBUS_SESSION_SOCKET_DIR /tmp) endif(WIN32) endif (NOT $ENV{TMP} STREQUAL "") endif (NOT $ENV{TEMP} STREQUAL "") endif (NOT $ENV{TMPDIR} STREQUAL "") # Not used on Windows, where there is no system bus set (DBUS_SYSTEM_PID_FILE ${DBUS_LOCALSTATEDIR}/run/dbus/pid) if (WIN32) set (DBUS_CONSOLE_AUTH_DIR "") else (WIN32) set (DBUS_CONSOLE_AUTH_DIR "/var/run/console/") endif (WIN32) # This won't work on Windows. It's not meant to - the system bus is # meaningless on Windows anyway. # # This has to be suitable for hard-coding in client libraries as well as # in the dbus-daemon's configuration, so it has to be valid to listen on # and also to connect to. If this ever changes, it'll need to be split into # two variables, one for the listening address and one for the connecting # address. set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=${DBUS_LOCALSTATEDIR}/run/dbus/system_bus_socket" CACHE STRING "system bus default address") if (WIN32) set (DBUS_SESSION_BUS_LISTEN_ADDRESS "autolaunch:" CACHE STRING "session bus default listening address") set (DBUS_SESSION_BUS_CONNECT_ADDRESS "autolaunch:" CACHE STRING "session bus fallback address for clients") set (DBUS_SYSTEM_CONFIG_FILE "share/dbus-1/system.conf") set (DBUS_SESSION_CONFIG_FILE "share/dbus-1/session.conf") # bus-test expects a non empty string set (DBUS_USER "Administrator") set (DBUS_TEST_USER "guest") set (DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL "") else (WIN32) set (DBUS_SESSION_BUS_LISTEN_ADDRESS "unix:tmpdir=${DBUS_SESSION_SOCKET_DIR}" CACHE STRING "session bus default listening address") set (DBUS_SESSION_BUS_CONNECT_ADDRESS "autolaunch:" CACHE STRING "session bus fallback address for clients") set (sysconfdir "") set (configdir ${sysconfdir}/dbus-1 ) set (DBUS_SYSTEM_CONFIG_FILE ${configdir}/system.conf) set (DBUS_SESSION_CONFIG_FILE ${configdir}/session.conf) set (DBUS_USER "messagebus") set (DBUS_TEST_USER "nobody") # For best security, assume that all non-Windows platforms can do # credentials-passing. set (DBUS_SESSION_CONF_MAYBE_AUTH_EXTERNAL "EXTERNAL") endif (WIN32) set (DBUS_DAEMON_NAME "dbus-daemon" CACHE STRING "The name of the dbus daemon executable") ########### create config.h ############### #include(ConfigureChecks.cmake) # better use flags for gcc if (MINGW) set (HAVE_GNUC_VARARGS 1) endif(MINGW) # compiler definitions add_definitions(-DHAVE_CONFIG_H=1) add_definitions(${DBUS_BUS_CFLAGS}) if (DBUS_BUILD_TESTS) # set variables used for the .in files (substituted by configure_file) in test/data: set(DBUS_TEST_EXEC ${EXECUTABLE_OUTPUT_PATH}${IDE_BIN}) set(DBUS_TEST_DATA ${CMAKE_BINARY_DIR}/test/data) set(TEST_SOCKET_DIR ${DBUS_SESSION_SOCKET_DIR} ) set(TEST_LAUNCH_HELPER_BINARY ${EXECUTABLE_OUTPUT_PATH}/dbus-daemon-launch-helper-test) set(TEST_BUS_LAUNCH_BINARY ${EXECUTABLE_OUTPUT_PATH}/dbus-launch${EXEEXT}) if (UNIX) set (TEST_LISTEN "unix:tmpdir=${TEST_SOCKET_DIR}") endif (UNIX) if (WIN32) set (TEST_LISTEN "tcp:host=localhost") endif (WIN32) endif (DBUS_BUILD_TESTS) set(DBUS_LIBRARIES dbus-1) set(DBUS_INTERNAL_LIBRARIES dbus-internal) set (DBUS_INTERNAL_ADD_LIBRARY_OPTIONS STATIC) set (DBUS_INTERNAL_CLIENT_DEFINITIONS "-DDBUS_COMPILATION") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ) if (WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dbus-env.bat.cmake ${CMAKE_BINARY_DIR}/bin/dbus-env.bat ) install_files(/bin FILES ${CMAKE_BINARY_DIR}/bin/dbus-env.bat) endif() add_definitions(-DHAVE_CONFIG_H=1) ########### subdirs ############### add_subdirectory( dbus ) add_subdirectory( bus ) if (DBUS_BUILD_TESTS) add_subdirectory( test ) add_custom_target(check COMMAND ctest -R ^test-.* ) endif (DBUS_BUILD_TESTS) add_subdirectory( tools ) add_subdirectory( doc ) OPTION(DBUS_INSTALL_SYSTEM_LIBS "install required system libraries" OFF) MESSAGE(" ") MESSAGE("set -DDBUS_INSTALL_SYSTEM_LIBS=1 to install runtime libraries too") MESSAGE("set DBUSDIR (environment or cmake option) to overwrite the default install directory ") MESSAGE(" ") MESSAGE(" ") GET_FILENAME_COMPONENT(C_COMPILER ${CMAKE_C_COMPILER} NAME) GET_FILENAME_COMPONENT(CXX_COMPILER ${CMAKE_CXX_COMPILER} NAME) message(" D-BUS ${DBUS_VERSION} ") message(" ============ ") message(" ") message(" install prefix: ${prefix} ") message(" install exec_prefix: ${exec_prefix} ") message(" install libdir: ${EXPANDED_LIBDIR} ") message(" install bindir: ${EXPANDED_BINDIR} ") message(" install sysconfdir: ${EXPANDED_SYSCONFDIR} ") message(" install datadir: ${EXPANDED_DATADIR} ") message(" source code location: ${DBUS_SOURCE_DIR} ") message(" build dir: ${CMAKE_BINARY_DIR} ") message(" c compiler: ${C_COMPILER} ") message(" cflags: ${CMAKE_C_FLAGS} ") message(" cflags debug: ${CMAKE_C_FLAGS_DEBUG} ") message(" cflags release: ${CMAKE_C_FLAGS_RELEASE} ") message(" cxx compiler: ${CXX_COMPILER} ") message(" cxxflags: ${CMAKE_CXX_FLAGS} ") message(" cxxflags debug: ${CMAKE_CXX_FLAGS_DEBUG} ") message(" cxxflags release: ${CMAKE_CXX_FLAGS_RELEASE} ") message(" 64-bit int: ${DBUS_INT64_TYPE} ") message(" 32-bit int: ${DBUS_INT32_TYPE} ") message(" 16-bit int: ${DBUS_INT16_TYPE} ") message(" Doxygen: ${DOXYGEN} ") message(" Docbook Generator: ${DOCBOOK_GENERATOR_NAME} ") message(" gcc coverage profiling: ${DBUS_GCOV_ENABLED} ") message(" Building unit tests: ${DBUS_BUILD_TESTS} ") message(" Building with GLib: ${DBUS_WITH_GLIB} ") message(" Building verbose mode: ${DBUS_ENABLE_VERBOSE_MODE} ") message(" Building w/o assertions: ${DBUS_DISABLE_ASSERT} ") message(" Building w/o checks: ${DBUS_DISABLE_CHECKS} ") message(" Building bus stats API: ${DBUS_ENABLE_STATS} ") message(" installing system libs: ${DBUS_INSTALL_SYSTEM_LIBS} ") message(" Building inotify support: ${DBUS_BUS_ENABLE_INOTIFY} ") message(" Building kqueue support: ${DBUS_BUS_ENABLE_KQUEUE} ") message(" Building Doxygen docs: ${DBUS_ENABLE_DOXYGEN_DOCS} ") message(" Building XML docs: ${DBUS_ENABLE_XML_DOCS} ") message(" Daemon executable name: ${DBUS_DAEMON_NAME}") if (WIN32) message(" System bus address: ${DBUS_SYSTEM_BUS_DEFAULT_ADDRESS} ") message(" Session bus listens on: ${DBUS_SESSION_BUS_LISTEN_ADDRESS} ") message(" Session clients connect to: ${DBUS_SESSION_BUS_CONNECT_ADDRESS} ") else (WIN32) message(" System bus socket: ${DBUS_SYSTEM_SOCKET} ") message(" System bus address: ${DBUS_SYSTEM_BUS_DEFAULT_ADDRESS} ") message(" System bus PID file: ${DBUS_SYSTEM_PID_FILE} ") message(" Session bus socket dir: ${DBUS_SESSION_SOCKET_DIR} ") message(" Console auth dir: ${DBUS_CONSOLE_AUTH_DIR} ") message(" System bus user: ${DBUS_USER} ") message(" 'make check' socket dir: ${TEST_SOCKET_DIR} ") endif (WIN32) message(" Test listen address: ${TEST_LISTEN} ") if (MSVC) message(" build timestamp: ${DBUS_BUILD_TIMESTAMP} ") endif (MSVC) MESSAGE(" ") if (DBUS_BUILD_TESTS) message("NOTE: building with unit tests increases the size of the installed library and renders it insecure.") endif(DBUS_BUILD_TESTS) if (DBUS_BUILD_TESTS AND DBUS_DISABLE_ASSERT) message("NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)") endif(DBUS_BUILD_TESTS AND DBUS_DISABLE_ASSERT) if (DBUS_GCOV_ENABLED) message("NOTE: building with coverage profiling is definitely for developers only.") endif(DBUS_GCOV_ENABLED) if (DBUS_ENABLE_VERBOSE_MODE) message("NOTE: building with verbose mode increases library size, may slightly increase security risk, and decreases performance.") endif(DBUS_ENABLE_VERBOSE_MODE) if(NOT DBUS_DISABLE_ASSERT) message("NOTE: building with assertions increases library size and decreases performance.") endif(NOT DBUS_DISABLE_ASSERT) if (DBUS_DISABLE_CHECKS) message("NOTE: building without checks for arguments passed to public API makes it harder to debug apps using D-BUS, but will slightly decrease D-BUS library size and _very_ slightly improve performance.") endif(DBUS_DISABLE_CHECKS) foreach(_note ${FOOTNOTES}) message(${_note}) endforeach() MESSAGE(" ") INCLUDE(modules/CPackInstallConfig.cmake) add_custom_target(help-options cmake -LH WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) dbus-1.10.6/cmake/tools/0000755000175000017500000000000012602773110014755 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/tools/CMakeLists.txt0000644000175000017500000000414712602773110017523 0ustar00smcvsmcv00000000000000add_definitions("-DDBUS_COMPILATION") set (dbus_send_SOURCES ../../tools/dbus-print-message.c ../../tools/dbus-print-message.h ../../tools/dbus-send.c ../../tools/tool-common.c ../../tools/tool-common.h ) set (dbus_monitor_SOURCES ../../tools/dbus-monitor.c ../../tools/dbus-print-message.c ../../tools/dbus-print-message.h ../../tools/tool-common.c ../../tools/tool-common.h ) set (dbus_test_tool_SOURCES ../../tools/dbus-echo.c ../../tools/dbus-spam.c ../../tools/tool-common.c ../../tools/tool-common.h ../../tools/test-tool.c ../../tools/test-tool.h ) set (dbus_update_activation_environment_SOURCES ../../tools/dbus-update-activation-environment.c ../../tools/tool-common.c ../../tools/tool-common.h ) if (WIN32) set (dbus_launch_SOURCES ../../tools/dbus-launch-win.c ) else (WIN32) set (dbus_launch_SOURCES ../../tools/dbus-launch.c ../../tools/tool-common.c ../../tools/tool-common.h ) endif (WIN32) if (DBUS_BUILD_X11) set (dbus_launch_SOURCES ${dbus_launch_SOURCES} ../../tools/dbus-launch-x11.c ) endif(DBUS_BUILD_X11) set (dbus_cleanup_sockets_SOURCES ../../tools/dbus-cleanup-sockets.c ) add_executable(dbus-send ${dbus_send_SOURCES}) target_link_libraries(dbus-send ${DBUS_LIBRARIES}) install_targets(/bin dbus-send ) add_executable(dbus-test-tool ${dbus_test_tool_SOURCES}) target_link_libraries(dbus-test-tool ${DBUS_LIBRARIES}) install_targets(/bin dbus-test-tool ) add_executable(dbus-update-activation-environment ${dbus_update_activation_environment_SOURCES}) target_link_libraries(dbus-update-activation-environment ${DBUS_LIBRARIES}) install_targets(/bin dbus-update-activation-environment ) add_executable(dbus-launch ${dbus_launch_SOURCES}) target_link_libraries(dbus-launch ${DBUS_LIBRARIES}) if (DBUS_BUILD_X11) target_link_libraries(dbus-launch ${X11_LIBRARIES} ) endif (DBUS_BUILD_X11) install_targets(/bin dbus-launch ) add_executable(dbus-monitor ${dbus_monitor_SOURCES}) target_link_libraries(dbus-monitor ${DBUS_LIBRARIES}) install_targets(/bin dbus-monitor ) # create the /var/lib/dbus directory for dbus-uuidgen install(DIRECTORY DESTINATION var/lib/dbus) dbus-1.10.6/cmake/test/0000755000175000017500000000000012627362053014603 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/test/CMakeLists.txt0000644000175000017500000001543312627362053017351 0ustar00smcvsmcv00000000000000include_directories(${CMAKE_SOURCE_DIR}/../test) add_definitions(${DBUS_INTERNAL_CLIENT_DEFINITIONS}) include_directories(${CMAKE_SOURCE_DIR}/../test) set(DBUS_SESSION_BUS_LISTEN_ADDRESS ${TEST_LISTEN}) add_library(dbus-testutils STATIC ${CMAKE_SOURCE_DIR}/../test/test-utils.h ${CMAKE_SOURCE_DIR}/../test/test-utils.c ) target_link_libraries(dbus-testutils ${DBUS_INTERNAL_LIBRARIES}) add_subdirectory( name-test ) set (manual-dir-iter_SOURCES ${CMAKE_SOURCE_DIR}/../test/manual-dir-iter.c ) set (test-service_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-service.c ) set (test-names_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-names.c ) set (break_loader_SOURCES ${CMAKE_SOURCE_DIR}/../test/break-loader.c ) set (test-shell-service_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-shell-service.c ) set (test-shell_SOURCES ${CMAKE_SOURCE_DIR}/../test/shell-test.c ) set (test-spawn_SOURCES ${CMAKE_SOURCE_DIR}/../test/spawn-test.c ) set (test-exit_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-exit.c ) set (test-segfault_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-segfault.c ) set (test-sleep-forever_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-sleep-forever.c ) set (manual-tcp_SOURCES ${CMAKE_SOURCE_DIR}/../test/manual-tcp.c ) set (manual-paths_SOURCES ${CMAKE_SOURCE_DIR}/../test/manual-paths.c ) add_helper_executable(manual-dir-iter ${manual-dir-iter_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-service ${test-service_SOURCES} dbus-testutils) add_helper_executable(test-names ${test-names_SOURCES} dbus-testutils) add_test_executable(test-shell ${test-shell_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_test_executable(test-printf ${CMAKE_SOURCE_DIR}/../test/internals/printf.c dbus-testutils) add_helper_executable(test-shell-service ${test-shell-service_SOURCES} dbus-testutils) add_helper_executable(test-spawn ${test-spawn_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-exit ${test-exit_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-segfault ${test-segfault_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-sleep-forever ${test-sleep-forever_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) add_test_executable(manual-tcp ${manual-tcp_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) if(WIN32) add_helper_executable(manual-paths ${manual-paths_SOURCES} ${DBUS_INTERNAL_LIBRARIES}) endif() if(DBUS_WITH_GLIB) message(STATUS "with glib test apps") add_library(dbus-testutils-glib STATIC ${CMAKE_SOURCE_DIR}/../test/test-utils-glib.h ${CMAKE_SOURCE_DIR}/../test/test-utils-glib.c ) target_link_libraries(dbus-testutils-glib dbus-testutils ${DBUS_INTERNAL_LIBRARIES}) add_definitions( ${GLIB2_DEFINITIONS} ${GOBJECT_DEFINITIONS} ) include_directories( ${GLIB2_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR} ) set(TEST_LIBRARIES ${DBUS_INTERNAL_LIBRARIES} dbus-testutils dbus-testutils-glib ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES}) add_test_executable(test-corrupt ${CMAKE_SOURCE_DIR}/../test/corrupt.c ${TEST_LIBRARIES}) add_test_executable(test-dbus-daemon ${CMAKE_SOURCE_DIR}/../test/dbus-daemon.c ${TEST_LIBRARIES}) add_test_executable(test-dbus-daemon-eavesdrop ${CMAKE_SOURCE_DIR}/../test/dbus-daemon-eavesdrop.c ${TEST_LIBRARIES}) add_test_executable(test-fdpass ${CMAKE_SOURCE_DIR}/../test/fdpass.c ${TEST_LIBRARIES}) add_test_executable(test-loopback ${CMAKE_SOURCE_DIR}/../test/loopback.c ${TEST_LIBRARIES}) add_test_executable(test-marshal ${CMAKE_SOURCE_DIR}/../test/marshal.c ${TEST_LIBRARIES}) add_test_executable(test-monitor ${CMAKE_SOURCE_DIR}/../test/monitor.c ${TEST_LIBRARIES}) add_test_executable(test-refs ${CMAKE_SOURCE_DIR}/../test/internals/refs.c ${TEST_LIBRARIES}) add_test_executable(test-relay ${CMAKE_SOURCE_DIR}/../test/relay.c ${TEST_LIBRARIES}) add_test_executable(test-syntax ${CMAKE_SOURCE_DIR}/../test/syntax.c ${TEST_LIBRARIES}) add_test_executable(test-syslog ${CMAKE_SOURCE_DIR}/../test/internals/syslog.c ${TEST_LIBRARIES}) add_helper_executable(manual-authz ${CMAKE_SOURCE_DIR}/../test/manual-authz.c ${TEST_LIBRARIES}) endif() ### keep these in creation order, i.e. uppermost dirs first set (TESTDIRS test/data test/data/valid-messages test/data/invalid-messages test/data/incomplete-messages test/data/auth test/data/sha-1 test/data/valid-config-files test/data/valid-config-files/basic.d test/data/valid-config-files/session.d test/data/valid-config-files-system test/data/valid-config-files-system/system.d test/data/valid-introspection-files test/data/valid-messages test/data/valid-service-files test/data/valid-service-files-system test/data/invalid-config-files test/data/invalid-config-files-system test/data/invalid-messages test/data/invalid-service-files-system test/data/equiv-config-files test/data/equiv-config-files/basic test/data/equiv-config-files/basic/basic.d test/data/equiv-config-files/entities test/data/equiv-config-files/entities/basic.d ) set (CONFIG_VERBOSE 0) FOREACH(DIR ${TESTDIRS}) FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${DIR}) ENDFOREACH(DIR) ### copy tests to builddir so that generated tests and static tests ### are all in one place. MESSAGE(STATUS "Copying test files to test directory") FOREACH(FILE_TYPE *.message *.message-raw *.auth-script *.sha1 *.txt *.conf *.service) FOREACH(DIR ${TESTDIRS}) FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../${DIR}/${FILE_TYPE}" ) FOREACH(FILE ${FILES}) GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME) SET (TARGET ${CMAKE_BINARY_DIR}/${DIR}/${FILENAME}) configure_file(${FILE} ${TARGET} COPYONLY) IF (CONFIG_VERBOSE) MESSAGE("${FILE}") ENDIF (CONFIG_VERBOSE) ENDFOREACH(FILE) ENDFOREACH(DIR) ENDFOREACH(FILE_TYPE) ### generate test files MESSAGE(STATUS "Generating test files from templates into test directory") FOREACH(FILE_TYPE *.conf.in *.service.in) FOREACH(DIR ${TESTDIRS}) FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../${DIR}/${FILE_TYPE}" ) FOREACH(FILE ${FILES}) GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME) STRING(REGEX REPLACE "\\.in$" "" FILENAME ${FILENAME}) SET (TARGET ${CMAKE_BINARY_DIR}/${DIR}/${FILENAME}) configure_file(${FILE} ${TARGET} @ONLY IMMEDIATE) IF (CONFIG_VERBOSE) MESSAGE("${FILE}") ENDIF (CONFIG_VERBOSE) ENDFOREACH(FILE) ENDFOREACH(DIR) ENDFOREACH(FILE_TYPE) MESSAGE(STATUS "Copying generated bus config files to test directory") configure_file("${CMAKE_SOURCE_DIR}/../bus/session.conf.in" ${CMAKE_BINARY_DIR}/test/data/valid-config-files/session.conf @ONLY) configure_file("${CMAKE_SOURCE_DIR}/../bus/system.conf.in" ${CMAKE_BINARY_DIR}/test/data/valid-config-files-system/system.conf @ONLY) dbus-1.10.6/cmake/test/name-test/0000755000175000017500000000000012602773110016471 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/test/name-test/CMakeLists.txt0000644000175000017500000000167712602773110021244 0ustar00smcvsmcv00000000000000if (DBUS_ENABLE_EMBEDDED_TESTS) set (NAMEtest-DIR ../../../test/name-test) add_definitions(${DBUS_INTERNAL_CLIENT_DEFINITIONS}) add_helper_executable(test-pending-call-dispatch ${NAMEtest-DIR}/test-pending-call-dispatch.c ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-pending-call-timeout ${NAMEtest-DIR}/test-pending-call-timeout.c ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-thread-init ${NAMEtest-DIR}/test-threads-init.c ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-ids ${NAMEtest-DIR}/test-ids.c ${DBUS_INTERNAL_LIBRARIES}) add_helper_executable(test-shutdown ${NAMEtest-DIR}/test-shutdown.c dbus-testutils) add_helper_executable(test-privserver ${NAMEtest-DIR}/test-privserver.c dbus-testutils) add_helper_executable(test-privserver-client ${NAMEtest-DIR}/test-privserver-client.c dbus-testutils) add_helper_executable(test-autolaunch ${NAMEtest-DIR}/test-autolaunch.c dbus-testutils) endif (DBUS_ENABLE_EMBEDDED_TESTS) dbus-1.10.6/cmake/modules/0000755000175000017500000000000012627362053015274 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/modules/Macros.cmake0000644000175000017500000000552212627362053017526 0ustar00smcvsmcv00000000000000if(DBUS_BUILD_TESTS AND CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Windows") if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") find_file(WINE_EXECUTABLE NAMES wine PATHS /usr/bin /usr/local/bin NO_CMAKE_FIND_ROOT_PATH ) find_file(HAVE_BINFMT_WINE_SUPPORT NAMES DOSWin wine Wine windows Windows PATHS /proc/sys/fs/binfmt_misc NO_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH ) if(WINE_EXECUTABLE AND HAVE_BINFMT_WINE_SUPPORT) list(APPEND FOOTNOTES "NOTE: The requirements to run cross compiled applications on your host system are achieved. You may run 'make check'.") endif() if(NOT WINE_EXECUTABLE) list(APPEND FOOTNOTES "NOTE: You may install the Windows emulator 'wine' to be able to run cross compiled test applications.") endif() if(NOT HAVE_BINFMT_WINE_SUPPORT) list(APPEND FOOTNOTES "NOTE: You may activate binfmt_misc support for wine to be able to run cross compiled test applications.") endif() else() list(APPEND FOOTNOTES "NOTE: You will not be able to run cross compiled applications on your host system.") endif() endif() MACRO(TIMESTAMP RESULT) if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE DATE) string(REGEX REPLACE "(..)[/.](..)[/.](....).*" "\\3\\2\\1" DATE ${DATE}) EXECUTE_PROCESS(COMMAND "cmd" " /C time /T" OUTPUT_VARIABLE TIME) string(REGEX REPLACE "(..):(..)" "\\1\\2" TIME ${TIME}) set (${RESULT} "${DATE}${TIME}") else () EXECUTE_PROCESS(COMMAND "date" "+%Y%m%d%H%M" OUTPUT_VARIABLE ${RESULT}) endif () ENDMACRO() macro(add_test_executable _target _source) add_executable(${_target} ${_source}) target_link_libraries(${_target} ${ARGN}) if (CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Windows") # run tests with binfmt_misc set(PREFIX "z:") set(_env "DBUS_TEST_DAEMON=${PREFIX}${CMAKE_BINARY_DIR}/bin/dbus-daemon${EXEEXT}") add_test(NAME ${_target} COMMAND $) else() set(PREFIX) set(_env "DBUS_TEST_DAEMON=${CMAKE_BINARY_DIR}/bin/dbus-daemon${EXEEXT}") add_test(NAME ${_target} COMMAND $) endif() list(APPEND _env "DBUS_SESSION_BUS_ADDRESS=") list(APPEND _env "DBUS_FATAL_WARNINGS=1") list(APPEND _env "DBUS_TEST_DATA=${PREFIX}${CMAKE_BINARY_DIR}/test/data") list(APPEND _env "DBUS_TEST_HOMEDIR=${PREFIX}${CMAKE_BINARY_DIR}/dbus") set_tests_properties(${_target} PROPERTIES ENVIRONMENT "${_env}") endmacro(add_test_executable) macro(add_helper_executable _target _source) add_executable(${_target} ${_source}) target_link_libraries(${_target} ${ARGN}) endmacro(add_helper_executable) dbus-1.10.6/cmake/modules/Win32Macros.cmake0000644000175000017500000000345312602773110020343 0ustar00smcvsmcv00000000000000# # win32 macros # # Copyright (c) 2006-2007, Ralf Habacker # # Redistribution and use is allowed according to the terms of the BSD license. # if (WIN32) # # addExplorerWrapper creates batch files for fast access # to the build environment from the win32 explorer. # # For mingw and nmake projects it's opens a command shell, # for Visual Studio IDE's (at least tested with VS 8 2005) it # opens the related .sln file with paths setting specified at # configure time. # MACRO (addExplorerWrapper _projectname) # write explorer wrappers get_filename_component(CMAKE_BIN_PATH ${CMAKE_COMMAND} PATH) set (ADD_PATH "${CMAKE_BIN_PATH}") if (QT_QMAKE_EXECUTABLE) get_filename_component(QT_BIN_PATH ${QT_QMAKE_EXECUTABLE} PATH) set (ADD_PATH "${ADD_PATH};${QT_BIN_PATH}") endif (QT_QMAKE_EXECUTABLE) # add here more pathes if (MINGW) get_filename_component(MINGW_BIN_PATH ${CMAKE_CXX_COMPILER} PATH) set (ADD_PATH "${ADD_PATH};${MINGW_BIN_PATH}") write_file (${CMAKE_BINARY_DIR}/${_projectname}-shell.bat "set PATH=${ADD_PATH};%PATH%\ncmd.exe") else (MINGW) if (CMAKE_BUILD_TOOL STREQUAL "nmake") get_filename_component(VC_BIN_PATH ${CMAKE_CXX_COMPILER} PATH) write_file (${CMAKE_BINARY_DIR}/${_projectname}-shell.bat "set PATH=${ADD_PATH};%PATH%\ncall \"${VC_BIN_PATH}\\vcvars32.bat\"\ncmd.exe") else (CMAKE_BUILD_TOOL STREQUAL "nmake") write_file (${CMAKE_BINARY_DIR}/${_projectname}-sln.bat "set PATH=${ADD_PATH};%PATH%\nstart ${_projectname}.sln") endif (CMAKE_BUILD_TOOL STREQUAL "nmake") endif (MINGW) ENDMACRO (addExplorerWrapper) endif(WIN32) dbus-1.10.6/cmake/modules/ProjectSourceGroup.cmake0000644000175000017500000000130312602773110022070 0ustar00smcvsmcv00000000000000# folders in the msvc projects # mode==flat : headers and ourses in no folders # mode==split : standard behavior of cmake, split headers and sources # mode== endforeach() endmacro() dbus-1.10.6/cmake/modules/MacroOptionalFindPackage.cmake0000644000175000017500000000153312602773110023115 0ustar00smcvsmcv00000000000000# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION() # MACRO_OPTIONAL_FIND_PACKAGE( [QUIT] ) # This macro is a combination of OPTION() and FIND_PACKAGE(), it # works like FIND_PACKAGE(), but additionally it automatically creates # an option name WITH_, which can be disabled via the cmake GUI. # or via -DWITH_=OFF # The standard _FOUND variables can be used in the same way # as when using the normal FIND_PACKAGE() MACRO (MACRO_OPTIONAL_FIND_PACKAGE _name ) OPTION(WITH_${_name} "Search for ${_name} package" ON) if (WITH_${_name}) FIND_PACKAGE(${_name} ${ARGN}) else (WITH_${_name}) set(${_name}_FOUND) set(${_name}_INCLUDE_DIR) set(${_name}_INCLUDES) set(${_name}_LIBRARY) set(${_name}_LIBRARIES) endif (WITH_${_name}) ENDMACRO (MACRO_OPTIONAL_FIND_PACKAGE) dbus-1.10.6/cmake/modules/MacroLibrary.cmake0000644000175000017500000000046712602773110020664 0ustar00smcvsmcv00000000000000# - include MacroLibrary offers a collection of macros which extend the built-in cmake commands # OPTIONAL_FIND_PACKAGE( [QUIT] ) INCLUDE(MacroOptionalFindPackage) #INCLUDE(MacroAdditionalCleanFiles) #INCLUDE(MacroAddFileDependencies) #INCLUDE(MacroGetenvWinPath) #INCLUDE(MacroEnsureOutOfSourceBuild) dbus-1.10.6/cmake/modules/MacroGetenvWinPath.cmake0000644000175000017500000000024612602773110021776 0ustar00smcvsmcv00000000000000 MACRO (MACRO_GETENV_WIN_PATH var name) set(${var} $ENV{${name}}) STRING(REGEX REPLACE "\\\\" "/" ${var} "${${var}}") ENDMACRO (MACRO_GETENV_WIN_PATH var name) dbus-1.10.6/cmake/modules/FindLibIconv.cmake0000644000175000017500000000322212602773110020574 0ustar00smcvsmcv00000000000000# - Try to find LibIconv # Once done this will define # # LIBICONV_FOUND - system has LibIconv # LIBICONV_INCLUDE_DIR - the LibIconv include directory # LIBICONV_LIBRARIES - the libraries needed to use LibIconv # LIBICONV_DEFINITIONS - Compiler switches required for using LibIconv if (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) # in cache already SET(LIBICONV_FOUND TRUE) else (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) IF (NOT WIN32) MESSAGE(FATAL_ERROR "Please set this to the correct values!") # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls INCLUDE(UsePkgConfig) PKGCONFIG(libiconv-1.9 _LibIconvIncDir _LibIconvLinkDir _LibIconvLinkFlags _LiIconvCflags) SET(LIBICONV_DEFINITIONS ${_LibIconvCflags}) ENDIF (NOT WIN32) FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h PATHS ${_LibIconvIncDir} PATH_SUFFIXES libiconv ) FIND_LIBRARY(LIBICONV_LIBRARIES NAMES iconv libiconv PATHS ${_LibIconvLinkDir} ) if (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) set(LIBICONV_FOUND TRUE) endif (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) if (LIBICONV_FOUND) if (NOT LibIconv_FIND_QUIETLY) message(STATUS "Found LibIconv: ${LIBICONV_LIBRARIES}") endif (NOT LibIconv_FIND_QUIETLY) else (LIBICONV_FOUND) if (LibIconv_FIND_REQUIRED) message(SEND_ERROR "Could NOT find LibIconv") endif (LibIconv_FIND_REQUIRED) endif (LIBICONV_FOUND) MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARIES) endif (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) dbus-1.10.6/cmake/modules/FindGObject.cmake0000644000175000017500000000301412602773110020403 0ustar00smcvsmcv00000000000000# - Try to find GObject # Once done this will define # # GOBJECT_FOUND - system has GObject # GOBJECT_INCLUDE_DIR - the GObject include directory # GOBJECT_LIBRARIES - the libraries needed to use GObject # GOBJECT_DEFINITIONS - Compiler switches required for using GObject # Copyright (c) 2011, Raphael Kubo da Costa # Copyright (c) 2006, Tim Beaulen # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. FIND_PACKAGE(PkgConfig) PKG_CHECK_MODULES(PC_GOBJECT gobject-2.0) SET(GOBJECT_DEFINITIONS ${PC_GOBJECT_CFLAGS_OTHER}) FIND_PATH(GOBJECT_INCLUDE_DIR gobject.h HINTS ${PC_GOBJECT_INCLUDEDIR} ${PC_GOBJECT_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/gobject/ ) FIND_LIBRARY(_GObjectLibs NAMES gobject-2.0 HINTS ${PC_GOBJECT_LIBDIR} ${PC_GOBJECT_LIBRARY_DIRS} ) FIND_LIBRARY(_GModuleLibs NAMES gmodule-2.0 HINTS ${PC_GOBJECT_LIBDIR} ${PC_GOBJECT_LIBRARY_DIRS} ) FIND_LIBRARY(_GThreadLibs NAMES gthread-2.0 HINTS ${PC_GOBJECT_LIBDIR} ${PC_GOBJECT_LIBRARY_DIRS} ) FIND_LIBRARY(_GLibs NAMES glib-2.0 HINTS ${PC_GOBJECT_LIBDIR} ${PC_GOBJECT_LIBRARY_DIRS} ) SET( GOBJECT_LIBRARIES ${_GObjectLibs} ${_GModuleLibs} ${_GThreadLibs} ${_GLibs} ) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GOBJECT DEFAULT_MSG GOBJECT_LIBRARIES GOBJECT_INCLUDE_DIR) MARK_AS_ADVANCED(GOBJECT_INCLUDE_DIR _GObjectLibs _GModuleLibs _GThreadLibs _GLibs) dbus-1.10.6/cmake/modules/FindGLib2.cmake0000644000175000017500000000353112602773110017771 0ustar00smcvsmcv00000000000000# - Try to find the GLIB2 libraries # Once done this will define # # GLIB2_FOUND - system has glib2 # GLIB2_INCLUDE_DIR - the glib2 include directory # GLIB2_LIBRARIES - glib2 library # Copyright (c) 2008 Laurent Montel, # Copyright (c) 2013 Ralf Habacker, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) # Already in cache, be silent set(GLIB2_FIND_QUIETLY TRUE) endif(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) if (NOT WIN32) find_package(PkgConfig) pkg_check_modules(PC_LibGLIB2 QUIET glib-2.0) endif() find_path(GLIB2_MAIN_INCLUDE_DIR NAMES glib.h HINTS ${PC_LibGLIB2_INCLUDEDIR} PATH_SUFFIXES glib-2.0) find_library(GLIB2_LIBRARY NAMES glib-2.0 HINTS ${PC_LibGLIB2_LIBDIR} ) find_library(GIO2_LIBRARY NAMES gio-2.0 HINTS ${PC_LibGLIB2_LIBDIR} ) set(GLIB2_LIBRARIES ${GLIB2_LIBRARY} ${GIO2_LIBRARY}) # search the glibconfig.h include dir under the same root where the library is found get_filename_component(glib2LibDir "${GLIB2_LIBRARY}" PATH) find_path(GLIB2_INTERNAL_INCLUDE_DIR glibconfig.h PATH_SUFFIXES glib-2.0/include HINTS ${PC_LibGLIB2_INCLUDEDIR} "${glib2LibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH}) set(GLIB2_INCLUDE_DIR "${GLIB2_MAIN_INCLUDE_DIR}") # not sure if this include dir is optional or required # for now it is optional if(GLIB2_INTERNAL_INCLUDE_DIR) set(GLIB2_INCLUDE_DIR ${GLIB2_INCLUDE_DIR} "${GLIB2_INTERNAL_INCLUDE_DIR}") endif(GLIB2_INTERNAL_INCLUDE_DIR) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLIB2 DEFAULT_MSG GLIB2_LIBRARIES GLIB2_MAIN_INCLUDE_DIR) mark_as_advanced(GLIB2_INCLUDE_DIR GLIB2_LIBRARIES) dbus-1.10.6/cmake/modules/FindDoxygen.cmake0000644000175000017500000000015612602773110020507 0ustar00smcvsmcv00000000000000 find_program(DOXYGEN_EXECUTABLE NAMES doxygen DOC "doxygen executable") mark_as_advanced(DOXYGEN_EXECUTABLE) dbus-1.10.6/cmake/modules/CheckStructMember.cmake0000644000175000017500000000214412602773110021642 0ustar00smcvsmcv00000000000000# - Check if the given struct or class has the specified member variable # CHECK_STRUCT_MEMBER (STRUCT MEMBER HEADER VARIABLE) # # STRUCT - the name of the struct or class you are interested in # MEMBER - the member which existence you want to check # HEADER - the header(s) where the prototype should be declared # VARIABLE - variable to store the result # # The following variables may be set before calling this macro to # modify the way the check is run: # # CMAKE_REQUIRED_FLAGS = string of compile command line flags # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) # CMAKE_REQUIRED_INCLUDES = list of include directories INCLUDE(CheckCXXSourceCompiles) MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT) SET(_INCLUDE_FILES) FOREACH (it ${_HEADER}) SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") ENDFOREACH (it) SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE " ${_INCLUDE_FILES} int main() { ${_STRUCT}* tmp; tmp->${_MEMBER}; return 0; } ") CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) ENDMACRO (CHECK_STRUCT_MEMBER) dbus-1.10.6/cmake/modules/CheckPrototypeExists.cmake0000644000175000017500000000206012602773110022430 0ustar00smcvsmcv00000000000000# - Check if the prototype for a function exists. # CHECK_PROTOTYPE_EXISTS (FUNCTION HEADER VARIABLE) # # FUNCTION - the name of the function you are looking for # HEADER - the header(s) where the prototype should be declared # VARIABLE - variable to store the result # # The following variables may be set before calling this macro to # modify the way the check is run: # # CMAKE_REQUIRED_FLAGS = string of compile command line flags # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) # CMAKE_REQUIRED_INCLUDES = list of include directories INCLUDE(CheckCXXSourceCompiles) MACRO (CHECK_PROTOTYPE_EXISTS _SYMBOL _HEADER _RESULT) SET(_INCLUDE_FILES) FOREACH (it ${_HEADER}) SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") ENDFOREACH (it) SET(_CHECK_PROTO_EXISTS_SOURCE_CODE " ${_INCLUDE_FILES} int main() { #ifndef ${_SYMBOL} int i = sizeof(&${_SYMBOL}); #endif return 0; } ") CHECK_CXX_SOURCE_COMPILES("${_CHECK_PROTO_EXISTS_SOURCE_CODE}" ${_RESULT}) ENDMACRO (CHECK_PROTOTYPE_EXISTS _SYMBOL _HEADER _RESULT) dbus-1.10.6/cmake/modules/CheckForAbstractSockets.c0000644000175000017500000000142412602773110022136 0ustar00smcvsmcv00000000000000#include #include #include #include #include #include int main() { int listen_fd; struct sockaddr_un addr; listen_fd = socket (PF_UNIX, SOCK_STREAM, 0); if (listen_fd < 0) { fprintf (stderr, "socket() failed: %s\n", strerror (errno)); exit (1); } memset (&addr, '\0', sizeof (addr)); addr.sun_family = AF_UNIX; strcpy (addr.sun_path, "X/tmp/dbus-fake-socket-path-used-in-configure-test"); addr.sun_path[0] = '\0'; /* this is what makes it abstract */ if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) { fprintf (stderr, "Abstract socket namespace bind() failed: %s\n", strerror (errno)); exit (1); } else exit (0); }dbus-1.10.6/cmake/modules/CPackInstallConfig.cmake0000644000175000017500000000322312602773110021725 0ustar00smcvsmcv00000000000000 if (DBUS_INSTALL_SYSTEM_LIBS) if (MINGW) install_files(/bin FILES ${LIBEXPAT_LIBRARIES}) else (MINGW) INCLUDE(InstallRequiredSystemLibraries) endif (MINGW) endif (DBUS_INSTALL_SYSTEM_LIBS) SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "D-BUS For Windows") SET(CPACK_PACKAGE_VENDOR "D-BUS Windows Team") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/../README") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/../COPYING") # duplicated from VERSION SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) #SET(CPACK_PACKAGE_INSTALL_DIRECTORY "dbus ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "dbus") IF(WIN32 AND NOT UNIX) SET(CPACK_GENERATOR NSIS ZIP) # can be NSIS, STGZ, TBZ2, TGZ, TZ and ZIP SET(CPACK_NSIS_COMPRESSOR "/SOLID lzma") # There is a bug in NSI that does not handle full unix paths properly. Make # sure there is at least one set of four (4) backlasshes. # SET(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/Utilities/Release\\\\InstallIcon.bmp") SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\dbus-launch.bat") SET(CPACK_NSIS_DISPLAY_NAME "D-Bus for Windows") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\sourceforge.net/projects/windbus") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\sourceforge.net/projects/windbus") SET(CPACK_NSIS_CONTACT "me@my-personal-home-page.com") SET(CPACK_NSIS_MODIFY_PATH ON) ELSE(WIN32 AND NOT UNIX) SET(CPACK_STRIP_FILES "bin/MyExecutable") SET(CPACK_SOURCE_STRIP_FILES "") ENDIF(WIN32 AND NOT UNIX) SET(CPACK_PACKAGE_EXECUTABLES "dbus-launch" "D-Bus Daemon") INCLUDE(CPack) dbus-1.10.6/cmake/modules/COPYING-CMAKE-SCRIPTS0000644000175000017500000000245612602773110020272 0ustar00smcvsmcv00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dbus-1.10.6/cmake/doc/0000755000175000017500000000000012602773110014362 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/doc/index.html.cmake0000644000175000017500000000175412602773110017445 0ustar00smcvsmcv00000000000000 D-Bus Documentation Index

    D-Bus Documentation Index

    Version @DBUS_VERSION_STRING@

    generic documentation application manuals
    D-Bus Website

    D-Bus Tutorial

    D-Bus Specification

    D-Bus FAQ

    D-Bus Test Plan

    D-Bus Daemon manual

    D-Bus launch manual

    D-Bus send tool manual

    D-Bus monitor manual
    dbus-1.10.6/cmake/doc/CMakeLists.txt0000644000175000017500000001557412602773110017136 0ustar00smcvsmcv00000000000000find_package(Doxygen) if(DOXYGEN_EXECUTABLE) OPTION(DBUS_ENABLE_DOXYGEN_DOCS "build DOXYGEN documentation (requires Doxygen)" ON) endif(DOXYGEN_EXECUTABLE) if (DBUS_ENABLE_DOXYGEN_DOCS) set (top_srcdir ${CMAKE_SOURCE_DIR}/..) configure_file(${CMAKE_SOURCE_DIR}/../Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile ) add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) endif (DBUS_ENABLE_DOXYGEN_DOCS) # # find docbook generator # find_program(MEINPROC4_EXECUTABLE meinproc4) find_program(XMLTO_EXECUTABLE xmlto) find_program(CYGPATH_EXECUTABLE cygpath) if (MEINPROC4_EXECUTABLE OR XMLTO_EXECUTABLE) OPTION(DBUS_ENABLE_XML_DOCS "build XML documentation (requires xmlto or meinproc4)" ON) ADD_CUSTOM_TARGET(xmldoc ALL) endif (MEINPROC4_EXECUTABLE OR XMLTO_EXECUTABLE) if (XMLTO_EXECUTABLE) set (DOCBOOK_GENERATOR_NAME "xmlto" PARENT_SCOPE) set(DBUS_XML_DOCS_ENABLED 1) set(MEINPROC4_EXECUTABLE 0) MESSAGE(STATUS "xmlto docbook generator found") set(STYLESHEET_MAN "${DOCBOOKXSL_DIR}/manpages/docbook.xsl") set(STYLESHEET_HTML "${DOCBOOKXSL_DIR}/html/docbook.xsl") elseif (MEINPROC4_EXECUTABLE) set(DOCBOOK_GENERATOR_NAME "meinproc4" PARENT_SCOPE) set(DBUS_XML_DOCS_ENABLED 1) if(WIN32) get_filename_component(_a ${MEINPROC4_EXECUTABLE} PATH) get_filename_component(_meinproc_install_path ${_a} PATH) set(STYLESHEET_HTML "${_meinproc_install_path}/share/apps/ksgmltools2/docbook/xsl/html/docbook.xsl") else(WIN32) set(STYLESHEET_HTML file:///usr/share/kde4/apps/ksgmltools2/customization/kde-nochunk.xsl) endif(WIN32) endif () if (DBUS_ENABLE_XML_DOCS) macro (DOCBOOK _sources _format) get_filename_component(_infile ${_sources} ABSOLUTE) get_filename_component(_name ${_infile} NAME) set(_deps ${CMAKE_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) if (${_format} STREQUAL "man") string(REPLACE ".xml" "" _outname ${_name}) set(STYLESHEET ${STYLESHEET_MAN}) else() string(REPLACE ".xml" ".html" _outname ${_name}) set(STYLESHEET ${STYLESHEET_HTML}) endif () set(_outfile ${CMAKE_CURRENT_BINARY_DIR}/${_outname}) if (EXISTS ${_sources}) if (MEINPROC4_EXECUTABLE) ADD_CUSTOM_COMMAND( OUTPUT ${_outfile} COMMAND ${MEINPROC4_EXECUTABLE} --stylesheet ${STYLESHEET} -o ${_outfile} ${_infile} DEPENDS ${_infile} ${STYLESHEET} ${_deps} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) endif () if (XMLTO_EXECUTABLE) if (MSYS) if (CYGPATH_EXECUTABLE) execute_process( COMMAND cygpath ${_infile} OUTPUT_VARIABLE _infile) else () execute_process(COMMAND dirname ${_infile} OUTPUT_VARIABLE _path) string(STRIP ${_path} _path) execute_process(COMMAND sh -c "cd ${_path}; pwd -W" OUTPUT_VARIABLE _path) string(STRIP ${_path} _path) set(_infile "${_path}/${_name}") endif(CYGPATH_EXECUTABLE) endif (MSYS) ADD_CUSTOM_COMMAND( OUTPUT ${_outfile} COMMAND ${XMLTO_EXECUTABLE} -vv ${_format} ${_infile} DEPENDS ${_infile} ${_deps} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) endif () if (${_format} STREQUAL "man") install(FILES ${_outfile} DESTINATION share/man/man1) else () install(FILES ${_outfile} DESTINATION share/doc/dbus) endif () else () MESSAGE(STATUS "skipping xml doc generating for ${_infile}, file not found") endif () ADD_CUSTOM_TARGET(${_outname} DEPENDS ${_outfile}) ADD_DEPENDENCIES(xmldoc ${_outname}) endmacro (DOCBOOK) ### copy tests to builddir so that generated tests and static tests ### are all in one place. ### todo how to add more filetypes MACRO (COPYDIR _src _type) FOREACH(FILE_TYPE ${_type}) FOREACH(DIR ${_src}) FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../${DIR}/${FILE_TYPE}" ) FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${DIR}) FOREACH(FILE ${FILES}) GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME) SET (TARGET ${CMAKE_BINARY_DIR}/${DIR}/${FILENAME}) configure_file(${FILE} ${TARGET} COPYONLY) IF (CONFIG_VERBOSE) MESSAGE("FROM: ${FILE}\nTO: ${TARGET}\n") ENDIF (CONFIG_VERBOSE) ENDFOREACH(FILE) ENDFOREACH(DIR) ENDFOREACH(FILE_TYPE) ENDMACRO (COPYDIR) COPYDIR(doc *.png) COPYDIR(doc *.svg) DOCBOOK(${CMAKE_SOURCE_DIR}/../doc/dbus-test-plan.xml html-nochunks) DOCBOOK(${CMAKE_SOURCE_DIR}/../doc/dbus-tutorial.xml html-nochunks) DOCBOOK(${CMAKE_SOURCE_DIR}/../doc/dbus-specification.xml html-nochunks) DOCBOOK(${CMAKE_SOURCE_DIR}/../doc/dbus-faq.xml html-nochunks) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-cleanup-sockets.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-daemon.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-launch.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-monitor.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-send.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-test-tool.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-update-activation-environment.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml) configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-uuidgen.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml html-nochunks) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml html-nochunks) if (UNIX) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml man) DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-update-activation-environment.1.xml man) endif() # # handle html index file # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index.html.cmake ${CMAKE_CURRENT_BINARY_DIR}/index.html ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/index.html DESTINATION share/doc/dbus) set (EXTRA_DIST ${CMAKE_SOURCE_DIR}/../doc/busconfig.dtd ${CMAKE_SOURCE_DIR}/../doc/introspect.dtd ${CMAKE_SOURCE_DIR}/../doc/introspect.xsl ) install(FILES ${EXTRA_DIST} DESTINATION share/doc/dbus) endif(DBUS_ENABLE_XML_DOCS) dbus-1.10.6/cmake/dbus/0000755000175000017500000000000012602773110014552 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/dbus/CMakeLists.txt0000644000175000017500000002315612602773110017321 0ustar00smcvsmcv00000000000000SET(DBUS_DIR ${CMAKE_SOURCE_DIR}/../dbus) configure_file(${DBUS_DIR}/dbus-arch-deps.h.in ${CMAKE_CURRENT_BINARY_DIR}/dbus-arch-deps.h ) add_definitions(-DDBUS_COMPILATION) set (dbusinclude_HEADERS ${DBUS_DIR}/dbus.h ${DBUS_DIR}/dbus-address.h ${DBUS_DIR}/dbus-bus.h ${DBUS_DIR}/dbus-connection.h ${DBUS_DIR}/dbus-errors.h ${DBUS_DIR}/dbus-macros.h ${DBUS_DIR}/dbus-memory.h ${DBUS_DIR}/dbus-message.h ${DBUS_DIR}/dbus-misc.h ${DBUS_DIR}/dbus-pending-call.h ${DBUS_DIR}/dbus-protocol.h ${DBUS_DIR}/dbus-server.h ${DBUS_DIR}/dbus-shared.h ${DBUS_DIR}/dbus-signature.h ${DBUS_DIR}/dbus-syntax.h ${DBUS_DIR}/dbus-threads.h ${DBUS_DIR}/dbus-types.h dbus-arch-deps.h ) ### source code that goes in the installed client library ### and is specific to library functionality set (DBUS_LIB_SOURCES ${DBUS_DIR}/dbus-address.c ${DBUS_DIR}/dbus-auth.c ${DBUS_DIR}/dbus-bus.c ${DBUS_DIR}/dbus-connection.c ${DBUS_DIR}/dbus-credentials.c ${DBUS_DIR}/dbus-errors.c ${DBUS_DIR}/dbus-keyring.c ${DBUS_DIR}/dbus-marshal-header.c ${DBUS_DIR}/dbus-marshal-byteswap.c ${DBUS_DIR}/dbus-marshal-recursive.c ${DBUS_DIR}/dbus-marshal-validate.c ${DBUS_DIR}/dbus-message.c ${DBUS_DIR}/dbus-misc.c ${DBUS_DIR}/dbus-nonce.c ${DBUS_DIR}/dbus-object-tree.c ${DBUS_DIR}/dbus-pending-call.c ${DBUS_DIR}/dbus-resources.c ${DBUS_DIR}/dbus-server.c ${DBUS_DIR}/dbus-server-socket.c ${DBUS_DIR}/dbus-server-debug-pipe.c ${DBUS_DIR}/dbus-sha.c ${DBUS_DIR}/dbus-signature.c ${DBUS_DIR}/dbus-syntax.c ${DBUS_DIR}/dbus-timeout.c ${DBUS_DIR}/dbus-threads.c ${DBUS_DIR}/dbus-transport.c ${DBUS_DIR}/dbus-transport-socket.c ${DBUS_DIR}/dbus-watch.c ) if(UNIX) set (DBUS_LIB_SOURCES ${DBUS_LIB_SOURCES} ${DBUS_DIR}/dbus-transport-unix.c ${DBUS_DIR}/dbus-server-unix.c ) else(UNIX) set (DBUS_LIB_SOURCES ${DBUS_LIB_SOURCES} ${DBUS_DIR}/dbus-transport-win.c ${DBUS_DIR}/dbus-server-win.c ) endif(UNIX) set (DBUS_LIB_HEADERS ${DBUS_DIR}/dbus-auth.h ${DBUS_DIR}/dbus-connection-internal.h ${DBUS_DIR}/dbus-credentials.h ${DBUS_DIR}/dbus-keyring.h ${DBUS_DIR}/dbus-marshal-header.h ${DBUS_DIR}/dbus-marshal-byteswap.h ${DBUS_DIR}/dbus-marshal-recursive.h ${DBUS_DIR}/dbus-marshal-validate.h ${DBUS_DIR}/dbus-message-internal.h ${DBUS_DIR}/dbus-message-private.h ${DBUS_DIR}/dbus-misc.h ${DBUS_DIR}/dbus-object-tree.h ${DBUS_DIR}/dbus-protocol.h ${DBUS_DIR}/dbus-resources.h ${DBUS_DIR}/dbus-server-debug-pipe.h ${DBUS_DIR}/dbus-server-protected.h ${DBUS_DIR}/dbus-server-unix.h ${DBUS_DIR}/dbus-sha.h ${DBUS_DIR}/dbus-timeout.h ${DBUS_DIR}/dbus-threads.h ${DBUS_DIR}/dbus-threads-internal.h ${DBUS_DIR}/dbus-transport.h ${DBUS_DIR}/dbus-transport-protected.h ${DBUS_DIR}/dbus-watch.h ${CMAKE_BINARY_DIR}/config.h ) if(UNIX) set (DBUS_LIB_HEADERS ${DBUS_LIB_HEADERS} ${DBUS_DIR}/dbus-transport-unix.h ) else(UNIX) set (DBUS_LIB_HEADERS ${DBUS_LIB_HEADERS} ${DBUS_DIR}/dbus-transport-win.h ) endif(UNIX) ### source code that goes in the installed client library ### AND is generic utility functionality used by the ### daemon or test programs (all symbols in here should ### be underscore-prefixed) set (DBUS_SHARED_SOURCES ${DBUS_DIR}/dbus-dataslot.c ${DBUS_DIR}/dbus-file.c ${DBUS_DIR}/dbus-hash.c ${DBUS_DIR}/dbus-internals.c ${DBUS_DIR}/dbus-list.c ${DBUS_DIR}/dbus-marshal-basic.c ${DBUS_DIR}/dbus-memory.c ${DBUS_DIR}/dbus-mempool.c ${DBUS_DIR}/dbus-string.c ${DBUS_DIR}/dbus-sysdeps.c ${DBUS_DIR}/dbus-pipe.c ) set (DBUS_SHARED_HEADERS ${DBUS_DIR}/dbus-dataslot.h ${DBUS_DIR}/dbus-file.h ${DBUS_DIR}/dbus-hash.h ${DBUS_DIR}/dbus-internals.h ${DBUS_DIR}/dbus-list.h ${DBUS_DIR}/dbus-marshal-basic.h ${DBUS_DIR}/dbus-mempool.h ${DBUS_DIR}/dbus-string.h ${DBUS_DIR}/dbus-string-private.h ${DBUS_DIR}/dbus-pipe.h ${DBUS_DIR}/dbus-sysdeps.h ) ### source code that is generic utility functionality used ### by the bus daemon or test apps, but is NOT included ### in the D-BUS client library (all symbols in here ### should be underscore-prefixed but don't really need ### to be unless they move to DBUS_SHARED_SOURCES later) set (DBUS_UTIL_SOURCES ${DBUS_DIR}/dbus-asv-util.c ${DBUS_DIR}/dbus-auth-script.c ${DBUS_DIR}/dbus-auth-util.c ${DBUS_DIR}/dbus-credentials-util.c ${DBUS_DIR}/dbus-mainloop.c ${DBUS_DIR}/dbus-marshal-byteswap-util.c ${DBUS_DIR}/dbus-marshal-recursive-util.c ${DBUS_DIR}/dbus-marshal-validate-util.c ${DBUS_DIR}/dbus-message-factory.c ${DBUS_DIR}/dbus-message-util.c ${DBUS_DIR}/dbus-shell.c ${DBUS_DIR}/dbus-socket-set.c ${DBUS_DIR}/dbus-socket-set-poll.c ${DBUS_DIR}/dbus-string-util.c ${DBUS_DIR}/dbus-sysdeps-util.c ) if (DBUS_ENABLE_EMBEDDED_TESTS) set (DBUS_UTIL_SOURCES ${DBUS_UTIL_SOURCES} ${DBUS_DIR}/dbus-test.c ) endif (DBUS_ENABLE_EMBEDDED_TESTS) set (DBUS_UTIL_HEADERS ${DBUS_DIR}/dbus-asv-util.h ${DBUS_DIR}/dbus-auth-script.h ${DBUS_DIR}/dbus-mainloop.h ${DBUS_DIR}/dbus-message-factory.h ${DBUS_DIR}/dbus-shell.h ${DBUS_DIR}/dbus-socket-set.h ${DBUS_DIR}/dbus-spawn.h ${DBUS_DIR}/dbus-test.h ) ### platform specific settings if (WIN32) set (DBUS_SHARED_SOURCES ${DBUS_SHARED_SOURCES} ${DBUS_DIR}/dbus-file-win.c ${DBUS_DIR}/dbus-init-win.cpp ${DBUS_DIR}/dbus-sysdeps-win.c ${DBUS_DIR}/dbus-pipe-win.c ${DBUS_DIR}/dbus-sysdeps-thread-win.c ) set (DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS} ${DBUS_DIR}/dbus-sockets-win.h ${DBUS_DIR}/dbus-sysdeps-win.h ) set (DBUS_UTIL_SOURCES ${DBUS_UTIL_SOURCES} ${DBUS_DIR}/dbus-spawn-win.c ${DBUS_DIR}/dbus-sysdeps-util-win.c ) if(WINCE) set (DBUS_SHARED_SOURCES ${DBUS_SHARED_SOURCES} ${DBUS_DIR}/dbus-sysdeps-wince-glue.c ) set (DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS} ${DBUS_DIR}/dbus-sysdeps-wince-glue.h ) endif(WINCE) else (WIN32) set (DBUS_SHARED_SOURCES ${DBUS_SHARED_SOURCES} ${DBUS_DIR}/dbus-file-unix.c ${DBUS_DIR}/dbus-pipe-unix.c ${DBUS_DIR}/dbus-sysdeps-unix.c ${DBUS_DIR}/dbus-sysdeps-pthread.c ${DBUS_DIR}/dbus-userdb.c ) set (DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS} ${DBUS_DIR}/dbus-server-unix.h ${DBUS_DIR}/dbus-transport-unix.h ${DBUS_DIR}/dbus-sysdeps-unix.h ${DBUS_DIR}/dbus-userdb.h ) set (DBUS_UTIL_SOURCES ${DBUS_UTIL_SOURCES} ${DBUS_DIR}/dbus-spawn.c ${DBUS_DIR}/dbus-userdb-util.c ${DBUS_DIR}/dbus-sysdeps-util-unix.c ) endif (WIN32) set(libdbus_SOURCES ${DBUS_LIB_SOURCES} ${DBUS_SHARED_SOURCES} ) set(libdbus_HEADERS ${DBUS_LIB_HEADERS} ${DBUS_SHARED_HEADERS} ) if (MSVC) set (BUILD_FILEVERSION ${DBUS_MAJOR_VERSION},${DBUS_MINOR_VERSION},${DBUS_MICRO_VERSION},${DBUS_PATCH_VERSION}) set (BUILD_TIMESTAMP ${DBUS_BUILD_TIMESTAMP}) configure_file(${DBUS_DIR}/versioninfo.rc.in ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/afxres.h "") list(APPEND libdbus_SOURCES versioninfo.rc) set_source_files_properties(versioninfo.rc COMPILE_FLAGS "-D__LINE__=1") endif (MSVC) if(MSVC_IDE) project_source_group(${GROUP_CODE} DBUS_LIB_SOURCES DBUS_LIB_HEADERS) project_source_group(${GROUP_CODE} DBUS_SHARED_SOURCES DBUS_SHARED_HEADERS) project_source_group(${GROUP_CODE} DBUS_UTIL_SOURCES DBUS_UTIL_SOURCES) endif(MSVC_IDE) ### Client library add_library(dbus-1 SHARED ${libdbus_SOURCES} ${libdbus_HEADERS} ) if(DEFINED DBUS_LIBRARY_REVISION) math(EXPR DBUS_LIBRARY_MAJOR "${DBUS_LIBRARY_CURRENT} - ${DBUS_LIBRARY_AGE}") endif() if(WIN32) if(DEFINED DBUS_LIBRARY_REVISION) set_target_properties(dbus-1 PROPERTIES SUFFIX "-${DBUS_LIBRARY_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}") add_custom_command(TARGET dbus-1 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "$/${CMAKE_SHARED_LIBRARY_PREFIX}dbus-1${CMAKE_SHARED_LIBRARY_SUFFIX}" COMMENT "Create non versioned dbus-1 library for legacy applications" ) install(FILES ${LEGACY_FILE_NAME} DESTINATION bin) endif() if(WINCE) target_link_libraries(dbus-1 ws2) else(WINCE) target_link_libraries(dbus-1 ws2_32 advapi32 netapi32 iphlpapi) endif(WINCE) else(WIN32) if(DEFINED DBUS_LIBRARY_REVISION) set_target_properties(dbus-1 PROPERTIES VERSION ${DBUS_LIBRARY_MAJOR}.${DBUS_LIBRARY_AGE}.${DBUS_LIBRARY_REVISION} SOVERSION ${DBUS_LIBRARY_MAJOR}) endif() target_link_libraries(dbus-1 ${CMAKE_THREAD_LIBS_INIT} rt) endif(WIN32) # Assume that Linux has -Wl,--version-script and other platforms do not if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") set(SOVERSION ${DBUS_LIBRARY_MAJOR}) configure_file(${DBUS_DIR}/Version.in ${CMAKE_CURRENT_BINARY_DIR}/Version) set_target_properties(dbus-1 PROPERTIES LINK_FLAGS -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/Version) endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") install(TARGETS dbus-1 ${INSTALL_TARGETS_DEFAULT_ARGS}) install_files(/include/dbus FILES ${dbusinclude_HEADERS}) ### Internal library, used for the daemon, tools and tests, compiled statically. add_library(dbus-internal ${DBUS_INTERNAL_ADD_LIBRARY_OPTIONS} ${DBUS_UTIL_SOURCES} ${DBUS_UTIL_HEADERS} ) target_link_libraries(dbus-internal dbus-1) if(WIN32) if(WINCE) target_link_libraries(dbus-internal ws2) else(WINCE) target_link_libraries(dbus-internal ws2_32 advapi32 netapi32 iphlpapi) endif(WINCE) else(WIN32) target_link_libraries(dbus-internal ${CMAKE_THREAD_LIBS_INIT} rt) endif(WIN32) if (DBUS_ENABLE_EMBEDDED_TESTS) add_test_executable(test-dbus ${CMAKE_SOURCE_DIR}/../dbus/dbus-test-main.c ${DBUS_INTERNAL_LIBRARIES}) set_target_properties(test-dbus PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS}) ENDIF (DBUS_ENABLE_EMBEDDED_TESTS) if (UNIX) # set version info ENDIF (UNIX) ## mop up the gcov files #clean-local: #/bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true dbus-1.10.6/cmake/dbus-env.bat.cmake0000644000175000017500000000034712602773110017113 0ustar00smcvsmcv00000000000000:: environment setting for dbus clients @echo off :: session bus address set DBUS_SESSION_BUS_ADDRESS=@DBUS_SESSION_BUS_CONNECT_ADDRESS@ :: system bus address set DBUS_SYSTEM_BUS_DEFAULT_ADDRESS=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ dbus-1.10.6/cmake/config.h.cmake0000644000175000017500000001573412602773110016324 0ustar00smcvsmcv00000000000000/* config.h. Generated by cmake from config.h.cmake */ #ifndef _DBUS_CONFIG_H #define _DBUS_CONFIG_H /****************************/ /* indicate that we are building with cmake */ #define DBUS_CMAKE 1 @AUTOPACKAGE_CONFIG_H_TEMPLATE@ /* * Variables defined by AC_DEFINE in ../configure.ac * should be placed in this file */ #cmakedefine HAVE_GNUC_VARARGS 1 #cmakedefine DBUS_CONSOLE_AUTH_DIR "@DBUS_CONSOLE_AUTH_DIR@" #cmakedefine DBUS_DATADIR "@DBUS_DATADIR@" #cmakedefine DBUS_BINDIR "@DBUS_BINDIR@" #cmakedefine DBUS_PREFIX "@DBUS_PREFIX@" #cmakedefine DBUS_SYSTEM_CONFIG_FILE "@DBUS_SYSTEM_CONFIG_FILE@" #cmakedefine DBUS_SESSION_CONFIG_FILE "@DBUS_SESSION_CONFIG_FILE@" #cmakedefine DBUS_DAEMON_NAME "@DBUS_DAEMON_NAME@" #cmakedefine DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@" #cmakedefine DBUS_SESSION_BUS_CONNECT_ADDRESS "@DBUS_SESSION_BUS_CONNECT_ADDRESS@" #cmakedefine DBUS_MACHINE_UUID_FILE "@DBUS_MACHINE_UUID_FILE@" #cmakedefine DBUS_DAEMONDIR "@DBUS_DAEMONDIR@" #cmakedefine DBUS_ENABLE_STATS #define TEST_LISTEN "@TEST_LISTEN@" // test binaries #define DBUS_TEST_EXEC "@DBUS_TEST_EXEC@" #define DBUS_EXEEXT "@EXEEXT@" #cmakedefine TEST_BUS_LAUNCH_BINARY "@TEST_BUS_LAUNCH_BINARY@" /* Some dbus features */ #cmakedefine DBUS_ENABLE_ANSI 1 #cmakedefine DBUS_ENABLE_VERBOSE_MODE 1 #cmakedefine DBUS_DISABLE_ASSERT 1 #ifndef DBUS_DISABLE_ASSERT # define DBUS_ENABLE_ASSERT 1 #endif #cmakedefine DBUS_DISABLE_CHECKS 1 #ifndef DBUS_DISABLE_CHECKS # define DBUS_ENABLE_CHECKS 1 #endif /* xmldocs */ /* doxygen */ #cmakedefine DBUS_GCOV_ENABLED 1 /* abstract-sockets */ #cmakedefine HAVE_ABSTRACT_SOCKETS 1 #cmakedefine DBUS_PATH_OR_ABSTRACT_VALUE 1 #if (defined DBUS_PATH_OR_ABSTRACT_VALUE) #define DBUS_PATH_OR_ABSTRACT @DBUS_PATH_OR_ABSTRACT_VALUE@ #endif #ifdef DBUS_PATH_OR_ABSTRACT_VALUE #undef DBUS_PATH_OR_ABSTRACT_VALUE #endif /* selinux */ /* kqueue */ #cmakedefine HAVE_CONSOLE_OWNER_FILE 1 #define DBUS_CONSOLE_OWNER_FILE "@DBUS_CONSOLE_OWNER_FILE@" #cmakedefine DBUS_HAVE_ATOMIC_INT 1 #cmakedefine DBUS_USE_ATOMIC_INT_486 1 #if (defined(__i386__) || defined(__x86_64__)) # define DBUS_HAVE_ATOMIC_INT 1 # define DBUS_USE_ATOMIC_INT_486 1 #endif #cmakedefine DBUS_BUILD_X11 1 /* For the moment, the cmake build system doesn't have an equivalent of * the autoconf build system's --disable-x11-autolaunch */ #ifdef DBUS_BUILD_X11 # define DBUS_ENABLE_X11_AUTOLAUNCH 1 #endif #define _DBUS_VA_COPY_ASSIGN(a1,a2) { a1 = a2; } #cmakedefine DBUS_VA_COPY_FUNC #if (defined DBUS_VA_COPY_FUNC) # define DBUS_VA_COPY @DBUS_VA_COPY_FUNC@ #endif #ifdef DBUS_VA_COPY_FUNC #undef DBUS_VA_COPY_FUNC #endif #cmakedefine DBUS_VA_COPY_AS_ARRAY @DBUS_VA_COPY_AS_ARRAY@ #cmakedefine DBUS_WITH_GLIB 1 #cmakedefine GLIB_VERSION_MIN_REQUIRED @GLIB_VERSION_MIN_REQUIRED@ #cmakedefine GLIB_VERSION_MAX_ALLOWED @GLIB_VERSION_MAX_ALLOWED@ // headers #cmakedefine HAVE_ALLOCA_H #cmakedefine HAVE_BYTESWAP_H #cmakedefine HAVE_CRT_EXTERNS_H /* Define to 1 if you have dirent.h */ #cmakedefine HAVE_DIRENT_H 1 #cmakedefine HAVE_DLFCN_H /* Define to 1 if you have errno.h */ #cmakedefine HAVE_ERRNO_H 1 #cmakedefine HAVE_EXECINFO_H #cmakedefine HAVE_EXPAT_H /* Define to 1 if you have grp.h */ #cmakedefine HAVE_GRP_H 1 /* Define to 1 if you have inttypes.h */ #cmakedefine HAVE_INTTYPES_H 1 /* Define to 1 if you have io.h */ #cmakedefine HAVE_IO_H 1 /* Define to 1 if you have locale.h */ #cmakedefine HAVE_LOCALE_H 1 #cmakedefine HAVE_MEMORY_H /* Define to 1 if you have sys/poll.h */ #cmakedefine HAVE_POLL 1 /* Define to 1 if you have signal.h */ #cmakedefine HAVE_SIGNAL_H 1 /* Define to 1 if you have stdint.h */ #cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_STDLIB_H /* Define to 1 if you have stdio.h */ #cmakedefine HAVE_STDIO_H 1 #cmakedefine HAVE_STRINGS_H #cmakedefine HAVE_STRING_H #cmakedefine HAVE_SYSLOG_H #cmakedefine HAVE_SYS_EVENTS_H #cmakedefine HAVE_SYS_INOTIFY_H #cmakedefine HAVE_SYS_PRCTL_H #cmakedefine HAVE_SYS_RESOURCE_H #cmakedefine HAVE_SYS_STAT_H /* Define to 1 if you have sys/syslimits.h */ #cmakedefine HAVE_SYS_SYSLIMITS_H 1 /* Define to 1 if you have sys/time.h */ #cmakedefine HAVE_SYS_TIME_H 1 #cmakedefine HAVE_SYS_TYPES_H #cmakedefine HAVE_SYS_UIO_H /* Define to 1 if you have sys/wait.h */ #cmakedefine HAVE_SYS_WAIT_H 1 /* Define to 1 if you have time.h */ #cmakedefine HAVE_TIME_H 1 /* Define to 1 if you have unistd.h */ #cmakedefine HAVE_UNISTD_H 1 /* Define to 1 if you have ws2tcpip.h */ #cmakedefine HAVE_WS2TCPIP_H // symbols /* Define to 1 if you have backtrace */ #cmakedefine HAVE_BACKTRACE 1 /* Define to 1 if you have getgrouplist */ #cmakedefine HAVE_GETGROUPLIST 1 /* Define to 1 if you have getpeerucred */ #cmakedefine HAVE_GETPEERUCRED 1 /* Define to 1 if you have nanosleep */ #cmakedefine HAVE_NANOSLEEP 1 /* Define to 1 if you have getpwnam_r */ #cmakedefine HAVE_POSIX_GETPWNAM_R 1 /* Define to 1 if you have socketpair */ #cmakedefine HAVE_SOCKETPAIR 1 /* Define to 1 if you have setenv */ #cmakedefine HAVE_SETENV 1 /* Define to 1 if you have unsetenv */ #cmakedefine HAVE_UNSETENV 1 /* Define to 1 if you have clearenv */ #cmakedefine HAVE_CLEARENV 1 /* Define to 1 if you have writev */ #cmakedefine HAVE_WRITEV 1 /* Define to 1 if you have socklen_t */ #cmakedefine HAVE_SOCKLEN_T 1 /* Define to 1 if you have setlocale */ #cmakedefine HAVE_SETLOCALE 1 /* Define to 1 if you have localeconv */ #cmakedefine HAVE_LOCALECONV 1 /* Define to 1 if you have strtoll */ #cmakedefine HAVE_STRTOLL 1 /* Define to 1 if you have strtoull */ #cmakedefine HAVE_STRTOULL 1 /* Define to 1 if you have pip2 */ #cmakedefine HAVE_PIPE2 #cmakedefine HAVE_ACCEPT4 1 #cmakedefine HAVE_DIRFD 1 #cmakedefine HAVE_INOTIFY_INIT1 1 #cmakedefine HAVE_UNIX_FD_PASSING 1 // structs /* Define to 1 if you have struct cmsgred */ #cmakedefine HAVE_CMSGCRED 1 #cmakedefine FD_SETSIZE @FD_SETSIZE@ #cmakedefine DBUS_USER "@DBUS_USER@" #cmakedefine DBUS_TEST_USER "@DBUS_TEST_USER@" // system type defines #if defined(_WIN32) || defined(_WIN64) || defined (_WIN32_WCE) # define DBUS_WIN # define DBUS_WIN_FIXME 1 # ifdef _WIN32_WCE # define DBUS_WINCE # else # define DBUS_WIN32 # endif #else # define DBUS_UNIX #endif #if defined(_WIN32) || defined(_WIN64) // mingw mode_t # ifdef HAVE_STDIO_H # include # endif # ifndef _MSC_VER # define uid_t int # define gid_t int # else # define snprintf _snprintf typedef int mode_t; # if !defined(_WIN32_WCE) # define strtoll _strtoi64 # define strtoull _strtoui64 # define HAVE_STRTOLL 1 # define HAVE_STRTOULL 1 # endif # endif #endif // defined(_WIN32) || defined(_WIN64) #ifdef interface #undef interface #endif #ifndef SIGHUP #define SIGHUP 1 #endif #cmakedefine DBUS_VERBOSE_C_S 1 #ifdef DBUS_VERBOSE_C_S #define _dbus_verbose_C_S printf #else #define _dbus_verbose_C_S _dbus_verbose #endif # if defined(_MSC_VER) && !defined(inline) #define inline __inline #endif #ifdef DBUS_WIN #define FD_SETSIZE @FD_SETSIZE@ #endif #endif // _DBUS_CONFIG_H dbus-1.10.6/cmake/bus/0000755000175000017500000000000012602773110014406 5ustar00smcvsmcv00000000000000dbus-1.10.6/cmake/bus/service.cmake0000644000175000017500000000010212602773110017041 0ustar00smcvsmcv00000000000000[D-BUS Service] Name=org.freedektop.DBus.ServiceName Exec=notepad dbus-1.10.6/cmake/bus/CMakeLists.txt0000644000175000017500000001555412602773110017160 0ustar00smcvsmcv00000000000000add_definitions(-DDBUS_COMPILATION) SET(EFENCE "") SET(BUS_DIR ${CMAKE_SOURCE_DIR}/../bus) # config files for installation CONFIGURE_FILE( "${BUS_DIR}/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/session.conf" IMMEDIATE @ONLY) CONFIGURE_FILE( "${BUS_DIR}/legacy-config/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/legacy-config/session.conf" IMMEDIATE @ONLY) FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/session.d) if(NOT WIN32) CONFIGURE_FILE( "${BUS_DIR}/system.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/system.conf" IMMEDIATE @ONLY) CONFIGURE_FILE( "${BUS_DIR}/legacy-config/system.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/legacy-config/system.conf" IMMEDIATE @ONLY) FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/system.d) endif() # copy services for local daemon start to local service dir data/dbus-1/services SET (SERVICE_FILES test/data/valid-service-files) FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../${SERVICE_FILES}/*.service.in" ) FOREACH(FILE ${FILES}) GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME_WE) SET (TARGET ${CMAKE_BINARY_DIR}/data/dbus-1/services/${FILENAME}.service) IF (CONFIG_VERBOSE) MESSAGE("FROM: ${FILE}\nTO: ${TARGET}\n") ENDIF (CONFIG_VERBOSE) configure_file(${FILE} ${TARGET} ) ENDFOREACH(FILE) SET (XML_SOURCES ${BUS_DIR}/config-loader-expat.c) if (DBUS_BUS_ENABLE_INOTIFY) set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-inotify.c) elseif (DBUS_BUS_ENABLE_KQUEUE) set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-kqueue.c) else (DBUS_BUS_ENABLE_INOTIFY) set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-default.c) endif (DBUS_BUS_ENABLE_INOTIFY) set (BUS_SOURCES ${BUS_DIR}/activation.c ${BUS_DIR}/activation.h ${BUS_DIR}/apparmor.c ${BUS_DIR}/apparmor.h ${BUS_DIR}/audit.c ${BUS_DIR}/audit.h ${BUS_DIR}/bus.c ${BUS_DIR}/bus.h ${BUS_DIR}/config-parser.c ${BUS_DIR}/config-parser.h ${BUS_DIR}/config-parser-common.c ${BUS_DIR}/config-parser-common.h # ${BUS_DIR}/config-parser-trivial.c ${BUS_DIR}/connection.c ${BUS_DIR}/connection.h ${BUS_DIR}/desktop-file.c ${BUS_DIR}/desktop-file.h ${BUS_DIR}/dir-watch.h ${BUS_DIR}/dispatch.c ${BUS_DIR}/dispatch.h ${BUS_DIR}/driver.c ${BUS_DIR}/driver.h ${BUS_DIR}/expirelist.c ${BUS_DIR}/expirelist.h ${BUS_DIR}/policy.c ${BUS_DIR}/policy.h ${BUS_DIR}/selinux.h ${BUS_DIR}/selinux.c ${BUS_DIR}/services.c ${BUS_DIR}/services.h ${BUS_DIR}/signals.c ${BUS_DIR}/signals.h ${BUS_DIR}/test.c ${BUS_DIR}/test.h ${BUS_DIR}/utils.c ${BUS_DIR}/utils.h ${XML_SOURCES} ${DIR_WATCH_SOURCE} ) if(DBUS_ENABLE_STATS) list(APPEND BUS_SOURCES ${BUS_DIR}/stats.c ${BUS_DIR}/stats.h ) endif(DBUS_ENABLE_STATS) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/.. ${XML_INCLUDE_DIR} ) add_executable(dbus-daemon ${BUS_SOURCES} ${BUS_DIR}/main.c) target_link_libraries(dbus-daemon ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) set_target_properties(dbus-daemon PROPERTIES OUTPUT_NAME ${DBUS_DAEMON_NAME}) set_target_properties(dbus-daemon PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS}) install_targets(/bin dbus-daemon) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/session.conf DESTINATION share/dbus-1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/legacy-config/session.conf DESTINATION etc/dbus-1) install(DIRECTORY DESTINATION share/dbus-1/session.d) install(DIRECTORY DESTINATION share/dbus-1/services) if(NOT WIN32) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/system.conf DESTINATION share/dbus-1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/legacy-config/system.conf DESTINATION etc/dbus-1) install(DIRECTORY DESTINATION share/dbus-1/system.d) install(DIRECTORY DESTINATION share/dbus-1/system-services) install(DIRECTORY DESTINATION var/run/dbus) endif() if (DBUS_SERVICE) set (dbus_service_SOURCES ${BUS_DIR}/bus-service-win.c # TODO: add additional files # ${BUS_DIR}/service-main.c # ${BUS_SOURCES} ) add_executable(dbus-service ${dbus_service_SOURCES} ) target_link_libraries(dbus-service ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) set_target_properties(dbus-service PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS}) install_targets(/bin dbus-service ) endif (DBUS_SERVICE) if (DBUS_ENABLE_EMBEDDED_TESTS) set(SOURCES ${BUS_SOURCES} ${BUS_DIR}/test-main.c) add_test_executable(test-bus "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) set_target_properties(test-bus PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS}) if (NOT WIN32) set(test_bus_system_SOURCES ${XML_SOURCES} ${BUS_DIR}/config-parser-common.c ${BUS_DIR}/config-parser-trivial.c ${BUS_DIR}/utils.c ${BUS_DIR}/test-system.c ) add_test_executable(test-bus-system "${test_bus_system_SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} ${DBUS_BUS_LIBS}) endif() endif (DBUS_ENABLE_EMBEDDED_TESTS) if(MSVC) project_source_group(${GROUP_CODE} bus_test_SOURCES dummy) endif(MSVC) ## mop up the gcov files #clean-local: # /bin/rm *.bb *.bbg *.da *.gcov || true #install-data-hook: # $(mkinstalldirs) $(DESTDIR)/$(localstatedir)/run/dbus # $(mkinstalldirs) $(DESTDIR)/$(configdir)/system.d # $(mkinstalldirs) $(DESTDIR)/$(datadir)/dbus-1/services ##install_file(${configdir}/system.d FILE set(LAUNCH_HELPER_SOURCES ${XML_SOURCES} ${BUS_DIR}/config-parser-common.c ${BUS_DIR}/config-parser-trivial.c ${BUS_DIR}/desktop-file.c ${BUS_DIR}/utils.c ${BUS_DIR}/activation-helper.c ) if(NOT WIN32) # TODO PENDING(kdab) fix build on windows (activation-helper.c) add_executable(dbus-daemon-launch-helper ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/activation-helper-bin.c ) target_link_libraries(dbus-daemon-launch-helper ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} ) add_executable(dbus-daemon-launch-helper-test ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/activation-helper-bin.c) set_target_properties(dbus-daemon-launch-helper-test PROPERTIES COMPILE_FLAGS "-DACTIVATION_LAUNCHER_TEST") target_link_libraries(dbus-daemon-launch-helper-test ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} ) set (SOURCES ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/test-launch-helper.c) add_test_executable(test-bus-launch-helper "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) set_target_properties(test-bus-launch-helper PROPERTIES COMPILE_FLAGS "-DACTIVATION_LAUNCHER_TEST -DACTIVATION_LAUNCHER_DO_OOM") install_targets(/lib dbus-daemon-launch-helper) endif(NOT WIN32) #### Init scripts fun #SCRIPT_IN_FILES=messagebus.in # rc.messagebus.in ## Red Hat start #if DBUS_INIT_SCRIPTS_RED_HAT #initddir=$(sysconfdir)/rc.d/init.d #initd_SCRIPTS= # messagebus #endif # ## Red Hat end ## Slackware start #if DBUS_INIT_SCRIPTS_SLACKWARE #initddir=$(sysconfdir)/rc.d/ #initd_SCRIPTS= # rc.messagebus #endif ## Slackware end #MAN_IN_FILES=dbus-daemon.1.in #man_MANS = dbus-daemon.1 #### Extra dist #EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) $(man_MANS) $(MAN_IN_FILES) dbus-1.10.6/cmake/bus-test.bat.cmake0000644000175000017500000000031412602773110017130 0ustar00smcvsmcv00000000000000:: bus-test wrapper @echo off :: session bus address set DBUS_STARTER_BUS=tcp:host=localhost,port=1234 if NOT "%1" == "" ( SET DATADIR=%1 ) else ( SET DATADIR=test\data ) bin\bus-test.exe test\data dbus-1.10.6/cmake/ConfigureChecks.cmake0000644000175000017500000001741412602773110017670 0ustar00smcvsmcv00000000000000include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckSymbolExists) include(CheckStructMember) include(CheckTypeSize) check_include_file(alloca.h HAVE_ALLOCA_H) check_include_file(byteswap.h HAVE_BYTESWAP_H) check_include_file(crt/externs.h HAVE_CRT_EXTERNS_H) check_include_file(dirent.h HAVE_DIRENT_H) # dbus-sysdeps-util.c check_include_file(dlfcn.h HAVE_DLFCN_H) check_include_file(execinfo.h HAVE_EXECINFO_H) check_include_file(errno.h HAVE_ERRNO_H) # dbus-sysdeps.c check_include_file(expat.h HAVE_EXPAT_H) check_include_file(grp.h HAVE_GRP_H) # dbus-sysdeps-util-win.c check_include_file(inttypes.h HAVE_INTTYPES_H) # dbus-pipe.h check_include_file(io.h HAVE_IO_H) # internal check_include_file(locale.h HAVE_LOCALE_H) check_include_file(memory.h HAVE_MEMORY_H) check_include_file(signal.h HAVE_SIGNAL_H) check_include_file(stdint.h HAVE_STDINT_H) # dbus-pipe.h check_include_file(stdlib.h HAVE_STDLIB_H) check_include_file(stdio.h HAVE_STDIO_H) # dbus-sysdeps.h check_include_file(string.h HAVE_STRING_H) check_include_file(strings.h HAVE_STRINGS_H) check_include_file(syslog.h HAVE_SYSLOG_H) check_include_files("stdint.h;sys/types.h;sys/event.h" HAVE_SYS_EVENT_H) check_include_file(sys/inotify.h HAVE_SYS_INOTIFY_H) check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(sys/uio.h HAVE_SYS_UIO_H) check_include_file(sys/poll.h HAVE_POLL) # dbus-sysdeps.c, dbus-sysdeps-win.c check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H) check_include_file(sys/syslimits.h HAVE_SYS_SYSLIMITS_H) # dbus-sysdeps-unix.c check_include_file(sys/time.h HAVE_SYS_TIME_H)# dbus-sysdeps-win.c check_include_file(sys/wait.h HAVE_SYS_WAIT_H)# dbus-sysdeps-win.c check_include_file(time.h HAVE_TIME_H) # dbus-sysdeps-win.c check_include_file(ws2tcpip.h HAVE_WS2TCPIP_H)# dbus-sysdeps-win.c check_include_file(unistd.h HAVE_UNISTD_H) # dbus-sysdeps-util-win.c check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE) # dbus-sysdeps.c, dbus-sysdeps-win.c check_symbol_exists(getgrouplist "grp.h" HAVE_GETGROUPLIST) # dbus-sysdeps.c check_symbol_exists(getpeerucred "ucred.h" HAVE_GETPEERUCRED) # dbus-sysdeps.c, dbus-sysdeps-win.c check_symbol_exists(nanosleep "time.h" HAVE_NANOSLEEP) # dbus-sysdeps.c check_symbol_exists(getpwnam_r "errno.h pwd.h" HAVE_POSIX_GETPWNAM_R) # dbus-sysdeps-util-unix.c check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) # dbus-sysdeps.c check_symbol_exists(unsetenv "stdlib.h" HAVE_UNSETENV) # dbus-sysdeps.c check_symbol_exists(clearenv "stdlib.h" HAVE_CLEARENV) # dbus-sysdeps.c check_symbol_exists(writev "sys/uio.h" HAVE_WRITEV) # dbus-sysdeps.c, dbus-sysdeps-win.c check_symbol_exists(setrlimit "sys/resource.h" HAVE_SETRLIMIT) # dbus-sysdeps.c, dbus-sysdeps-win.c, test/test-segfault.c check_symbol_exists(socketpair "sys/socket.h" HAVE_SOCKETPAIR) # dbus-sysdeps.c check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE) # dbus-test-main.c check_symbol_exists(localeconv "locale.h" HAVE_LOCALECONV) # dbus-sysdeps.c check_symbol_exists(strtoll "stdlib.h" HAVE_STRTOLL) # dbus-send.c check_symbol_exists(strtoull "stdlib.h" HAVE_STRTOULL) # dbus-send.c set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_symbol_exists(pipe2 "fcntl.h;unistd.h" HAVE_PIPE2) check_symbol_exists(accept4 "sys/socket.h" HAVE_ACCEPT4) check_symbol_exists(dirfd "dirent.h" HAVE_DIRFD) check_symbol_exists(inotify_init1 "sys/inotify.h" HAVE_INOTIFY_INIT1) check_symbol_exists(SCM_RIGHTS "sys/types.h;sys/socket.h;sys/un.h" HAVE_UNIX_FD_PASSING) check_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL) check_symbol_exists(raise "signal.h" HAVE_RAISE) check_struct_member(cmsgcred cmcred_pid "sys/types.h sys/socket.h" HAVE_CMSGCRED) # dbus-sysdeps.c # missing: # HAVE_ABSTRACT_SOCKETS # DBUS_HAVE_GCC33_GCOV check_type_size("short" SIZEOF_SHORT) check_type_size("int" SIZEOF_INT) check_type_size("long" SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("__int64" SIZEOF___INT64) set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") check_type_size("socklen_t" SOCKLEN_T) # dbus-sysdeps-unix.c set(CMAKE_EXTRA_INCLUDE_FILES) # DBUS_INT64_TYPE if(SIZEOF_INT EQUAL 8) set (DBUS_INT64_TYPE "int") set (DBUS_INT64_CONSTANT "(val)") set (DBUS_UINT64_CONSTANT "(val##U)") elseif(SIZEOF_LONG EQUAL 8) set (DBUS_INT64_TYPE "long") set (DBUS_INT64_CONSTANT "(val##L)") set (DBUS_UINT64_CONSTANT "(val##UL)") elseif(SIZEOF_LONG_LONG EQUAL 8) set (DBUS_INT64_TYPE "long long") set (DBUS_INT64_CONSTANT "(val##LL)") set (DBUS_UINT64_CONSTANT "(val##ULL)") elseif(SIZEOF___INT64 EQUAL 8) set (DBUS_INT64_TYPE "__int64") set (DBUS_INT64_CONSTANT "(val##i64)") set (DBUS_UINT64_CONSTANT "(val##ui64)") else(SIZEOF_INT EQUAL 8) message (FATAL_ERROR "Could not find a 64-bit integer type") endif(SIZEOF_INT EQUAL 8) # DBUS_INT32_TYPE if(SIZEOF_INT EQUAL 4) set (DBUS_INT32_TYPE "int") elseif(SIZEOF_LONG EQUAL 4) set (DBUS_INT32_TYPE "long") elseif(SIZEOF_LONG_LONG EQUAL 4) set (DBUS_INT32_TYPE "long long") endif(SIZEOF_INT EQUAL 4) # DBUS_INT16_TYPE if(SIZEOF_INT EQUAL 2) set (DBUS_INT16_TYPE "int") elseif(SIZEOF_SHORT EQUAL 2) set (DBUS_INT16_TYPE "short") endif(SIZEOF_INT EQUAL 2) find_program(DOXYGEN doxygen) find_program(XMLTO xmlto) if(MSVC) SET(DBUS_VA_COPY_FUNC "_DBUS_VA_COPY_ASSIGN") else(MSVC) write_file("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/cmake_try_compile.c" "#include #include static void f (int i, ...) { va_list args1, args2; va_start (args1, i); va_copy (args2, args1); if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) exit (1); va_end (args1); va_end (args2); } int main() { f (0, 42); return 0; } ") try_compile(DBUS_HAVE_VA_COPY ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/cmake_try_compile.c) if(DBUS_HAVE_VA_COPY) SET(DBUS_VA_COPY_FUNC va_copy CACHE STRING "va_copy function") else(DBUS_HAVE_VA_COPY) write_file("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/cmake_try_compile.c" "#include #include static void f (int i, ...) { va_list args1, args2; va_start (args1, i); __va_copy (args2, args1); if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) exit (1); va_end (args1); va_end (args2); } int main() { f (0, 42); return 0; } ") try_compile(DBUS_HAVE___VA_COPY ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/cmake_try_compile.c) if(DBUS_HAVE___VA_COPY) SET(DBUS_VA_COPY_FUNC __va_copy CACHE STRING "va_copy function") else(DBUS_HAVE___VA_COPY) SET(DBUS_VA_COPY_AS_ARRAY "1" CACHE STRING "'va_lists' cannot be copies as values") endif(DBUS_HAVE___VA_COPY) endif(DBUS_HAVE_VA_COPY) endif(MSVC) # _not_ MSVC #### Abstract sockets if (DBUS_ENABLE_ABSTRACT_SOCKETS) try_compile(HAVE_ABSTRACT_SOCKETS ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/modules/CheckForAbstractSockets.c) endif(DBUS_ENABLE_ABSTRACT_SOCKETS) if(HAVE_ABSTRACT_SOCKETS) set(DBUS_PATH_OR_ABSTRACT_VALUE abstract) else(HAVE_ABSTRACT_SOCKETS) set(DBUS_PATH_OR_ABSTRACT_VALUE path) endif(HAVE_ABSTRACT_SOCKETS) dbus-1.10.6/README.launchd0000644000175000017500000000606212602773110015036 0ustar00smcvsmcv00000000000000Launchd[1,2] replaces init, inetd and cron on Mac OS X since 10.4 "Tiger". dbus uses this service to provide a common session bus address for each user and so deprecates the X11 enabled dbus-launcher. [1] http://developer.apple.com/MacOsX/launchd.html [2] http://launchd.macosforge.org/ Setup === Configure with --enable-launchd and --without-x (X11 should not harm but it's simply not necessary any more) After installation, to prevent a reboot, load the dbus session starter into launchd by executing: $ launchctl load /Library/LaunchAgents/org.freedesktop.dbus-session.plist You can change the launch agent dir via configure, but it's not recommended. Make sure to execute the above line as the actual user for which you want to use a session bus since launchd manages its agents on a per user basis. How it works === Launchd allocates a socket and provides the unix path to it via the variable DBUS_LAUNCHD_SESSION_BUS_SOCKET in launchd's environment. Every process spawned by launchd (or dbus-daemon, if stared by launchd) can access it through its own environment. Other processes can query launchd for it by executing: $ launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET However, this is normally done by the dbus client lib for you. If launchd start dbus-daemon with a config file containing a "launchd:env=FOO" address, as the default session config does with env=DBUS_LAUNCHD_SESSION_BUS_SOCKET, the daemon will get the file descriptor from launchd and start listening on it. The environment variable is used to get the actual socket path which is passed to every service spawned by dbus-daemon as a result from autolaunch messages. Please note that it's not possible to start dbus-daemon manually when using a "launchd:" address. Only child processes of launchd can access the above mentioned file descriptor! To create custom buses just set up an other launch agent. As a quick start copy /Library/LaunchAgents/org.freedesktop.dbus-session.plist, change the label to i.e. "org.freedesktop.dbus-foo" and change the SecureSocketWithKey value, i.e. to "DBUS_LAUNCHD_FOO_BUS_SOCKET". This environment variable has to be set in the config file for your new bus in the element (see session.config). Then edit your /Library/LaunchAgents/org.freedesktop.dbus-foo.plist to start dbus-daemon with "--config-file=/opt/local/etc/dbus-1/foo.conf" instead of "--session". Now load the new plist onto launchd as described in the setup section of this document. Executing "launchctl export" should now give you two sockets, one in DBUS_LAUNCHD_SESSION_BUS_SOCKET and the new DBUS_LAUNCHD_FOO_BUS_SOCKET. To connect to this new bus use "launchd:env=DBUS_LAUNCHD_FOO_BUS_SOCKET". Since Mac OS X 10.5 "Leopard" you can also configure launchd to start dbus-daemon on demand as soon as some process connects to the socket. Since it's broken on 10.4 this feature is disabled per default. Look at /Library/LaunchAgents/org.freedesktop.dbus-session.plist to change it. On the client side, the envvar DBUS_SESSION_BUS_ADDRESS can be normally used but if it's not set, launchd is queried for the session bus socket. dbus-1.10.6/README.cygwin0000755000175000017500000000024512602773110014720 0ustar00smcvsmcv00000000000000The cygwin dbus port is included in master branch of dbus git repository since 1.3.1. The cygwin port of dbus is maintained by: http://sourceware.org/cygwinports/ dbus-1.10.6/README.wince0000644000175000017500000000523512602773110014526 0ustar00smcvsmcv00000000000000DBus Daemon for Windows CE/Windows Mobile 6.5 ============================================= Bugs in upstream for any window version: * MoveFileExA < 0 result check bug * double dbus_free somewhere I forgot where (check in -ugly) * alignment issue * CreateProcess process information handle leak * _dbus_getsid NULL vs INVALID_HANDLE_VALUE * win_account_to_sid Customisation ============= 1) At installation, the following registry value should be set to the installation directory of the dbus installation (the directory containing the bin, etc, share folders): HKLM\Software\freedesktop\DBus\Install Directory 2) Instead of environment variable DBUS_VERBOSE, use HKLM\Software\freedesktop\DBus\Verbose 2) The keyring directory is MYDOCUMENTS\dbus-keyrings, not HOMEPATH\.dbus-keyrings. Compilation =========== ./configure --host=arm-mingw32ce CPPFLAGS=-I/path/to/expat/include LDFLAGS=-L/path/to/expat/lib A recent version of libtool is required, with this change: 2010-02-28 Pierre Ossman (tiny change) Ralf Wildenhues Fix deplibs check fallback for 64-bit Windows and Windows CE. * libltdl/m4/libtool.m4 (_LT_CHECK_MAGIC_METHOD): Accept file formats 'pe-arm-wince' and 'pe-x86-64'. Add note about consistency with ... * libltdl/config/ltmain.m4sh (func_win32_libid): ... the respective pattern here; sync pattern from the former. * tests/deplibs-mingw.at (deplibs without file command): New file, new test. * Makefile.am (TESTSUITE_AT): Update. * NEWS: Update. MB vs WCHAR =========== Windows CE only supports the Unicode interface, while DBus Daemon uses the Multi-Byte interface on Windows by default. The glue code does not support multibyte in all cases. In particular, the _mbsrchr function is not correctly implemented. It could be correctly implemented, or dbus daemon could use the wchar interface more consistently on all Windows targets. For now, the Windows CE port will only work for filesystems without some weird characters in file names. Is this a serious limitation? Known Issues ============ Autolaunch is broken so far. Environment variables are faked. Some are punted to the registry, but in any case they can not be used reliably for IPC. The test suite is not ported yet. dbus-pipe.c: * Uses libc file descriptors. Needed for --print-address and --print-pid which probably don't work yet. dbus-sysdeps-win.c: * Backtraces have been disabled. * _dbus_fd_set_close_on_exec Not supported, maybe we should disable the warning. * SearchPathA: Uses HKLM\\Software\\freedesktop\\DBus\\Install Directory to locate binaries. dbus-1.10.6/README.win0000644000175000017500000000766112602773110014223 0ustar00smcvsmcv00000000000000----------------------------------------- Windows port of the freedesktop.org D-Bus ----------------------------------------- Features and completeness ------------------------- The windows port of dbus provides the dbus-1 library and mostly applications which are already available on unix. These applications are: dbus-daemon, dbus-launch, dbus-monitor and dbus-send. DBus comes with a test suite which is used on unix to guarantate production quality and this test suite runs mostly. There are some test not running yet and there is help needed to get them running. Supported compilers ------------------- On windows Microsoft Visual Studio 2010 (Express and professional variants) and mingw-w64|32 are known to work. Building -------- DBus can be built on windows using automake or cmake. See the file INSTALL for more information. windbus and dbus4win Ports -------------------------- The Windows ports from the windbus and dbus4win projects has been merged into the freedesktop git master branch, as applicable. The spec has been updated with windows specific stuff. Tests ----- - run complete test suite make check or ctest [-V] - dbus library check ctest [-V] -R test-dbus - bus daemon check ctest [-V] -R test-bus - check available names ctest [-V] -R test-names - check if dbus-daemon is accessable bin\dbus-send.exe --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames method return sender=org.freedesktop.DBus -> dest=:1.4 array [ string "org.freedesktop.DBus"string ":1.4"] - start session dbus-daemon either by running bin\dbus-launch or start bin\dbus-daemon --session Before running these commands you may execute set DBUS_VERBOSE=1 for getting debug infos - call function registerd in dbus bin\dbus-send.exe --dest=org.freedesktop.DBus --print-reply --type=method_call / org.freedesktop.DBus.StartServiceByName string:org.freedesktop.DBus.TestSuiteEchoService uint32:455 method return sender=org.freedesktop.DBus -> dest=:1.8 uint32 2 note: When building with the Visual C++ IDE the *.exe files are in the bin/Debug and bin/Release folder, not in the bin folder. FAQ --- - How far is WinDBus from being usable for production ? dbus comes with a test suite which is used on unix to guarantate production quality and this test suite runs mostly. There are some test not running and we need help to get them running. In the pratice I and some other people are using dbus for at least more than four years in conjunction with kde on windows without any problems. - On UNIX D-Bus uses UNIX sockets to communicate (correct me if I'm wrong). What is used on Windows ? tcp sockets, there are some efforts to get named pipe running, but some design problems of the win32 api, we are not able to solve without bigger changes to the dbus code base let us stop this effort. - Do you have any clue if dbus-win32 can run in a Windows CE environment? dbus has been ported to wince, see README.wince for more information - Do you know if the C++ binding made by OpenWengo will be easily portable to Windows? The OpenWengo dbus-c++ binding has been ported to windows see in WinDBus svn (http://sf.net/projects/windbus) The related test applications are running well. TODO ---- October 2010: - the code wrapped with DBUS_WIN_FIXME should be inspected if it required for windows - create a dbus setup installer - implement system bus and system bus service starter see http://windbus.svn.sourceforge.net/viewvc/windbus/trunk/bus/bus-service-win.c for a starting point - implement a real login session bus The scope parameter of the autolaunch meta protocol could be extended to support user specific session busses (like already done with the amarok bundled dbus which use a shared memory area named "DBusDaemonAddressInfo:". Also the dbus installer should start a session bus on user login. dbus-1.10.6/README.valgrind0000644000175000017500000000147712602773110015233 0ustar00smcvsmcv00000000000000Running D-Bus clients with Valgrind ==== When running programs using libdbus in Valgrind, some special care needs to be taken so as to avoid incorrect detection of leaks in libdbus. To avoid these false positives, do the following: * Grab a copy of the D-Bus source code * Run configure with the --enable-developer and --with-valgrind options * Run make * Either make sure your code calls dbus_shutdown() (at least while running in Valgrind) or set DBUS_MESSAGE_CACHE=0 in your environment * Run Valgrind on your program with the /path/to/dbus/source/dbus/.libs in your LD_LIBRARY_PATH Your Valgrind log should now be free of any (spurious) libdbus-related leaks. For the curious, the DBUS_MESSAGE_CACHE=0 is required because by default, libdbus uses a recyclable pool of message structs. These help performance a bit. dbus-1.10.6/NEWS.pre-1-20000644000175000017500000001477212602773110014331 0ustar00smcvsmcv00000000000000D-Bus 1.2.1 (04 April) == - Due to issues putting the re-licensing effort on hold indefinitely, it has been decided to move to 1.2.x versioning scheme. Being that 1.1.20 is considered to also be 1.2.0 and this being the second release in the 1.2.x stable series we have versioned this release 1.2.1. This release contains a number of bug fixes identified after 1.1.20. - compiles under some older versions of glibc - compiles without X support once again - fix stuck server grab if dbus-launch is run in an existing D-Bus X session - various Mac OSX build fixes added - don't use the broken poll call on Mac OSX - better checks for linker flag support should allow D-Bus to link under various linkers - exit_on_disconnect is set after the connection registers with a bus so we don't exit if we get a disconnect during the handshake - dicts now work correctly with dbus-send - inotify backend is now less aggressive - pending calls expire correctly - memleak of uuid when the bus is autolaunched fixed D-Bus 1.1.20 - "Conisten Water" (27 Febuary) == - This is the next generation supported STABLE release of D-Bus. For all intents and purposes this is the 1.2.0 release WITHOUT the planned X11/MIT license change due to a couple of license holders who have yet to respond. For the most part this license change is being persued to simplify licensing issues and fix a couple of licensing courner cases. When this happens D-Bus will be released under the 1.2.0 version. - D-Bus 1.0.x effectively goes into security fix mode and will only be updated for major issues. - Fixed CVE-2008-0595 - security policy of the type work as an implicit allow for messages sent without an interface bypassing the default deny rules and potentially allowing restricted methods exported on the bus to be executed by unauthorized users. - Fixes dbus-launch so the session bus goes away so does D-Bus - Builds against latest gcc/glibc changes - Correctly unref connections without guids during shutdown - About the name: Submitted by Greg K Nicholson, Conisten Water is a lake in Cumbria, England where several water speed records have been broken. Between 1956 and 1959 Sir Malcolm's son Donald Campbell set four successive records on the lake in Bluebird K7, a hydroplane. (Wikipedia http://en.wikipedia.org/wiki/Coniston_Water#Waterspeed_record) D-Bus 1.1.4 - 1.2.0RC2 (17 January 2007) == - Fixes inotify support D-Bus 1.1.3 - 1.2.0RC1 (15 January 2007) == - This release is intended to be Release Candidate 1 of major release D-Bus 1.2.0. If nothing is found to be wrong with this release it will become 1.2.0 within a week. If we need to make major changes we will release an RC2 and start the process over again. - This is a development release, so API's may still change if problems are found (though this is extreamly unlikely). - DTD for the introspection format is fixed and uploaded to the servers - Sources now reside in a git repository at http://gitweb.freedesktop.org/?p=dbus/dbus.git;a=summary - Argument path matching of the type arg0path='/aa/bb/' is now supported (see the specification for more information) - New error org.freedesktop.DBus.Error.ObjectPathInUse added - Autolaunched busses now save their parameters in X11 if possible making them behave closer to busses launched through the normal mechanisms - inotify is now the default backend for watching configuration file changes - More support for the AIX platform has been added - Numerous bug fixes and performance enhancements D-Bus 1.1.2 (27 July 2007) == - This release is intended to be a feature complete beta for stable release 1.2.0, please test it. 1.2.0 will follow pretty soon if no major problems are found. We'll do more betas if significant changes are made. - This is a development release, so API's may still change if problems are found (though we will try hard not to). - The system bus now supports starting services on demand. This uses a setuid helper program because system bus daemon runs as a nobody user, while services it launches may need to run as a different user. ***Extra eyes auditing the setuid helper are encouraged and would be timely right now, before 1.2.0*** A design doc is available in doc/system-activation.txt - The TCP address format has been enhanced, such that TCP may be actually usable. The dbus-daemon man page describes the new elements in the address format. 1.1.1 had added an all_interfaces flag to the format, which has been removed in favor of a cleaner approach. - Some thread-related bugs have been fixed, these are important fixes if you are using multiple threads with libdbus, and not important otherwise. D-Bus 1.1.1 (18 June 2007) == - This is a development release, unless you need specific functionality please use the stable releases as API's may change (though we will try hard not to) - The bus daemon now generates a globally-unique ID for itself, which is available using the convenience function dbus_bus_get_id(). Use this as a unique ID for a user's session, for example. - dbus_server_get_id(), dbus_connection_get_server_id() now available to access the unique ID of a particular address - dbus_watch_get_fd() deprecated since it had unclear cross-platform semantics. dbus_watch_get_unix_fd() and dbus_watch_get_socket() replace it. - support ANONYMOUS mechanism for authentication, which allows a client to authenticate as nobody in particular - add API dbus_connection_set_allow_anonymous() which will allow the message stream to begin if the client auths as anonymous (otherwise, the client will be dropped unless they auth as a user). - the ANONYMOUS support means you can now use D-Bus (without a bus daemon) as a protocol for a network service provided to anonymous Internet or LAN clients - many internal changes to better support the Windows port, though the port is still not complete in this release - some improved documentation and return_if_fail checks - some small bug fixes D-Bus 1.1.0 (25 May 2007) == - first release in the development series, unless you need specific functionality please use the stable releases as API's may change (though we will try hard not to) - better eavesdropping support now picks up reply messages for debugging - .pc file now lists the directory the daemon is installed into (daemondir) - GetAll call added to the properties interface - support for message serialization added for use with external transports like TUBES!!! - many bugs fixed dbus-1.10.6/ChangeLog.pre-1-20000644000175000017500000021577412602773110015411 0ustar00smcvsmcv000000000000002008-04-04 John (J5) Palmieri * Released 1.2.1 2008-04-03 John (J5) Palmieri Patch from Sumit , comments added * dbus/dbus-transport.c(_dbus_transport_open): fix mem leak 2008-04-03 John (J5) Palmieri * dbus/dbus-connection.c (dbus_connection_send): add documentation to describe when to call dbus_connection_flush and dbus_connection_unref after a call to dbus_connection_send is made Initial wording by Stanislav Brabec (fd.o bug#13558) 2008-04-03 John (J5) Palmieri Patch from Kimmo Hämäläinen * bus/expirelist.c (do_expiration_with_current_time): calculate correct min wait time and next interval (bus_expire_list_add, bus_expire_list_add_link): if the timeout is disabled when we add an item to the expire list, enable the timeout (do_expiration_with_current_time): only set timeout if there are items to expire 2008-04-01 Timo Hoenig Patch from Frederic Crozat * bus/dir-watch-inotify.c (bus_watch_directory): Only monitor IN_CLOSE_WRITE, IN_DELETE, IN_MOVE_TO and IN_MOVE_FROM events. This way, only atomic changes to configuration file are monitored. * bus/dir-watch-inotify.c (_handle_inotify_watch): Fix typo in _dbus_verbose function call * bus/dir-watch-inotify.c (bus_drop_all_directory_watches): Use _dbus_strerror instead of perror 2008-03-04 Havoc Pennington * bus/connection.c, bus/expirelist.c: Make the BusExpireList struct opaque, adding accessors for manipulating the list. In this commit there should be no change in functionality or behavior. The purpose of this change is to improve encapsulation prior to fixing some bugs Kimmo Hämäläinen found where the timeout is not properly updated, since we need to e.g. take some action whenever adding and removing stuff from the expire list. 2008-03-31 Colin Walters Patch from Owen Taylor * tools/dbus-launch-x11.c: Check for X11 events before selecting (FDO bug #15293) 2008-03-31 Colin Walters Patch from Owen Taylor * tools/dbus-launch-x11.c: Make sure we call XFlush() on all code paths (FDO bug #15293) 2008-03-27 Havoc Pennington * tools/dbus-send.c (append_dict): Do not provide a signature to dbus_message_iter_open_container() when opening a dict entry. 2008-03-26 Colin Walters Patch from Scott James Remnant * dbus/dbus-bus.c: Set default exit_on_disconnect after registration with the bus, not before. This ensures that programs which wish to set exit_on_disconnect to FALSE will not be terminated if the bus exits during registration. (FDO Bug #15112) 2008-03-04 John (J5) Palmieri * fix broken poll on Mac OSX - build patch by Benjamin Reed * configure.in: check for OSX's deadlocking poll * dbus/dbus-sysdeps-unix.c (_dbus_poll): if we have a broken poll don't use poll 2008-03-04 John (J5) Palmieri * check if the linker supports a flag instead of just checking for GNU ld * configure.in: move AM_PROG_LIBTOOL to the top (ld_supports_flag): new function for checking if the linker supports a given flag 2008-03-04 John (J5) Palmieri * add a changelog for Benjamin Reed's git patch RANT: Change Logs are handled by git and having an external changelog just screws up merging. We should write down rules for doing git commit messages and leave it at that. * configure.in: Platform build fixes for Mac OS X the Darwin linker does not understand the -z option; wrap it in a check for $with_gnu_ld. environ is only available at runtime, so you need to make a reference to _NSGetEnviron instead for symbols to resolve properly. 2008-03-04 John (J5) Palmieri * configure.in: add $THREAD_LIBS to DBUS_LAUNCHER_LIBS so we link correctly 2008-03-04 John (J5) Palmieri * tools/dbus-launch.c: wrap X'ism in #ifdef so we can compile without X 2008-02-28 John (J5) Palmieri * dbus/dbus-sysdeps-unix.c: define _AI_ADDRCONFIG as 0 if not defined so that we can compile with an older glibc 2008-02-26 John (J5) Palmieri * Released 1.1.20 2008-02-26 John (J5) Palmieri * CVE-2008-0595 - security policy of the type work as an implicit allow for messages sent without an interface bypassing the default deny rules and potentially allowing restricted methods exported on the bus to be executed by unauthorized users. This patch fixes the issue. * bus/policy.c (bus_client_policy_check_can_send, bus_client_policy_check_can_receive): skip messages without an interface when evaluating an allow rule, and thus pass it to the default deny rules 2008-02-26 John (J5) Palmieri * correctly unref connections without guids during shutdown * dbus/dbus-connection.c (close_connection_on_shutdown): new method split out from shared_connections_shutdown (shared_connections_shutdown): shutdown all shared connections without guids (_dbus_connection_ref_unlocked): handle OOM when prepending no guid connections to the shared_connections_no_guid list * Patch by Kimmo Hämäläinen 2008-02-21 John (J5) Palmieri * fix build against the latest gcc/glibc * dbus/dbus-sysdeps-unix.c: define _GNU_SOURCE * bus/selinux.c: include limits.h * Patch by Matthias Clasen 2008-02-21 John (J5) Palmieri * fixes dbus-launch so the bus goes away when X does (Red Hat Bug #430412) * tools/dbus-launch.c (main): set xdisplay = NULL * Patch by Matthias Clasen 2008-01-17 John (J5) Palmieri * Released 1.1.4 2008-01-17 Timo Hoenig * fix inotify support * bus/dir-watch-inotify.c (_handle_inotify_watch): fix reading of the inotify events. Also, use ssize_t not size_t for 'ret'. * bus/dir-watch-inotify.c (bus_watch_directory): watch not only for IN_MODIFY but also for IN_CREATE and IN_DELETE * bus/dir-watch-inotify.c (bus_drop_all_directory_watches): drop the inotify watches more elegantly by closing inotify:_fd, set inotify_fd to -1 after dropping the watches 2008-01-15 John (J5) Palmieri * configure.in: post-release version bump 2008-01-15 John (J5) Palmieri * Released 1.1.3 (1.2.0RC1) 2008-01-15 John (J5) Palmieri * fix hacking to say git instead of cvs 2008-01-15 John (J5) Palmieri * patch by Sébastien Couret <10function at gmail dot com> * dbus/dbus-marshal-recursive.c (all_reader_classes[]): wrap in #ifndef DBUS_DISABLE_ASSERT since it is only used in asserts which are noop 2008-01-15 John (J5) Palmieri * patch by Magnus Henoch * dbus/dbus-auth.c (handle_server_data_external_mech): handle SASL EXTERNAL's inital empty responce (FDO Bug #9945) 2008-01-15 John (J5) Palmieri * bus/messagebus.in: add lsb headers (FDO Bug #11491) 2008-01-15 John (J5) Palmieri * patch by Peter O'Gorman * dbus/dbus-spawn.c (babysit_signal_handler): check write return value so we don't hang (FDO Bug #11665) 2008-01-15 John (J5) Palmieri * patch by Peter O'Gorman * dbus/dbus-sysdeps.h: support for AIX poll implementation (FDO Bug #11666) 2008-01-15 John (J5) Palmieri * tests/name-test/run-test.sh: make more portable (FDO Bug #11667) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-connection.c (_dbus_connection_get_next_client_serial): don't check for < 0 on an unsigned variable (FDO Bug #12924) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * bus/bus.c (setup_server): check failed allocation (FDO Bug #12920) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): the API contract says sitter_p can be NULL, so let's check it (FDO Bug #12919) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-spawn.c (read_ints, read_pid): use correct ssize_t type instead of size_t (FDO Bug #12862) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-errors.c (dbus_set_error): make sure to call va_end if we hit an OOM error inside va_start (FDO Bug #12846) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-connection.c (dbus_connection_send_with_reply): fix possible crash if pending_return is NULL (FDO Bug #12673) 2008-01-15 John (J5) Palmieri * portions of patch submitted by Tim Mooney * configure.in: never auto-select libxml (FDO Bug #12479) 2008-01-15 John (J5) Palmieri * patches by Kimmo Hämäläinen * dbus/dbus-sysdeps-unix (_dbus_get_autolaunch_address): handle OOM (FDO Bug #12945) * dbus/dbus-uuidgen.c (return_uuid): handle OOM (FDO Bug #12928) * dbus/dbus-misc.c (dbus_get_local_machine_id): handle OOM, fix return value to return NULL not FALSE (FDO Bug #12946) 2008-01-15 John (J5) Palmieri * bus/bus.c (bus_context_check_security_policy): rewrite selinux error handling to not abort due to a NULL read and to set the error only if it is not already set (Based off of FDO Bug #12430) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-internals.c (_dbus_read_uuid_file_without_creating, _dbus_create_uuid_file_exclusively): add OOM handling (FDO Bug #12952) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-spawn.c (babysit, babysitter_iteration): add error handling when polling (FDO Bug #12954) 2008-01-15 John (J5) Palmieri * patch by Kimmo Hämäläinen * bus/config-parser.c (locate_attributes): remove dead code which always evaluated to TRUE * dbus/dbus-shell.c (_dbus_shell_quote): remove unused code 2008-01-14 John (J5) Palmieri * patch by Kimmo Hämäläinen * bus/connection.c (bus_connection_complete): plug a possible BusClientPolicy leak (FDO Bug #13242) 2008-01-14 John (J5) Palmieri * patch by Frederic Crozat (FDO Bz# 13268) * add inotify support * bus/Makefile.am: add inotify module to the build * bus/dir-watch-inotify.c: inotify module based off the dnotify and kqueue modules * configure.in: add checks and switch for inotify also add a printout at the end of configure if inotify and kqueue support is being built in (dnotify already had this) 2008-01-14 John (J5) Palmieri * patch by Frederic Crozat * bus/dir-watch-dnotify.c (bus_watch_directory): watch for file creates also 2008-01-14 John (J5) Palmieri * patch by Kimmo Hämäläinen * dbus/dbus-transport-socket.c(do_reading): return message loader buffer in case of OOM (FDO Bug#12666) 2008-01-14 John (J5) Palmieri * configure.in: add warning to output when libxml is selected since we don't have a libxml maintainer and expat works perfectly fine for what we need an xml parser for 2008-01-14 John (J5) Palmieri * Patch by Andrea Luzzardi : creates a _dbus_geteuid function to fix EXTERNAL authentication in setuid applications * dbus/dbus-sysdeps-unix.c (_dbus_geteuid): used to get the effective uid of the running program (_dbus_credentials_add_from_current_process): use geteuid instead of getuid (_dbus_append_user_from_current_process): use geteuid instead of getuid * dbus/dbus-sysdeps-util-unix.c (_dbus_change_to_daemon_user): use geteuid instead of getuid (_dbus_unix_user_is_at_console): use geteuid instead of getuid * dbus/dbus-sysdeps-win.c (_dbus_geteuid): add a windows equivilant that returns DBUS_UID_UNSET 2007-12-18 Havoc Pennington * dbus/dbus-connection.c (_dbus_connection_block_pending_call): fix location of curly braces 2007-11-23 Sjoerd Simons * tools/dbus-launch.c: let both a normal dbus-launch and an autolaunched bus save their parameters in X11 if possible. This makes the autolaunch and non-autolaunch behaviour more similar. With the exception that on a normal launch there will always be a new session bus and not being able to save parameters is not fatal. This also enables to launch programs directly with autolaunch (not very usefull though). 2007-10-31 Havoc Pennington * bus/selinux.c (log_audit_callback): rewrite to use _dbus_string_copy_to_buffer_with_nul() * dbus/dbus-string.c (_dbus_string_copy_to_buffer): change to NOT nul-terminate the buffer; fail an assertion if there is not enough space in the target buffer. This fixes two bugs where copy_to_buffer was used to copy the binary bytes in a UUID, where nul termination did not make sense. Bug reported by David Castelow. (_dbus_string_copy_to_buffer_with_nul): new function that always nul-terminates the buffer, and fails an assertion if there is not enough space in the buffer. 2007-10-23 Havoc Pennington * bus/bus.c (bus_context_new): use the new name here * bus/selinux.c (bus_selinux_audit_init): rename from audit_init() to avoid possible libc conflict, and declare it in .h file to avoid a warning 2007-10-19 Havoc Pennington * bus/bus.c (bus_context_new): put audit_init() in HAVE_SELINUX 2007-10-19 Havoc Pennington * bus/bus.c (bus_context_new): put the audit_init() in here instead, which I believe ends up being the same as where it was before, though I'm not sure I understand why it goes here. * dbus/dbus-sysdeps-util-unix.c (_dbus_change_to_daemon_user): remove audit_init() from here, this file can't depend on code in bus/ directory 2007-10-16 Simon McVittie * configure.in: *Actually* fix detection of i486 atomic ops - my previous attempt at a fix would always enable them due to wrong quoting. Patch from Colin Walters 2007-10-11 Simon McVittie * configure.in: enable Autoconf's AC_C_INLINE to avoid compilation failure with gcc -ansi * dbus/dbus-macros.h, dbus/dbus-arch-deps.h.in: Use new macro _DBUS_GNUC_EXTENSION (the same as G_GNUC_EXTENSION) to avoid -ansi warnings about use of "long long". * dbus/dbus-server-socket.c: remove unused variable when assertions are disabled * dbus/dbus-marshal-validate.c: avoid empty statements by removing stray semicolons * tools/dbus-launch.c: convert C++-style comment to C-style, add {} for clarity * .gitignore: ignore vi swapfiles * dbus/dbus-errors.h, dbus/dbus-errors.c: Add DBUS_ERROR_INIT macro, equivalent to calling dbus_error_init() on an uninitialized DBusError * dbus/dbus-address.c, dbus/dbus-auth-script.c, dbus/dbus-auth-util.c, dbus/dbus-connection.c, dbus/dbus-internals.c, dbus/dbus-keyring.c, dbus/dbus-message-util.c, dbus/dbus-server.c, dbus/dbus-sha.c, dbus/dbus-spawn-win.c, dbus/dbus-spawn.c, dbus/dbus-sysdeps-util-win.c, dbus/dbus-transport-socket.c, dbus/dbus-transport.c, dbus/dbus-userdb.c: use that macro instead of calling dbus_error_init() where it's clearly equivalent * configure.in, dbus/dbus-sysdeps.h, dbus/dbus-sysdeps-unix.c: Fix detection of i486 atomic ops. Previously, the attempts to determine support at compile-time on Darwin were causing the i486 atomic ops to be used on *all* i386 or x86-64 GCC builds (AH_VERBATIM can't be conditionalized like we were trying to). 2007-10-10 Simon McVittie * dbus/dbus-errors.c, dbus/dbus-protocol.h: Add new error org.freedesktop.DBus.Error.ObjectPathInUse * dbus/dbus-object-tree.h, dbus/dbus-object-tree.c, dbus/dbus-connection.c, dbus/dbus-connection.h: add new functions dbus_connection_try_register_object_path and dbus_connection_try_register_fallback, which raise ObjectPathInUse rather than asserting, to make object path registration less painful for bindings * .gitignore: add various things that weren't in .cvsignore because CVS implicitly ignored them; generally bring up to date 2007-10-09 John (J5) Palmieri * tools/run-with-tmp-session-bus.sh: Fix env exports for better portability (#9280) * tools/dbus-send.1: Document syntax for container types in dbus-send man file (#9553) - patch from Jack Spaar [Both OK for MIT/X11 relicensing -smcv] 2007-10-09 Simon McVittie * doc/dbus-specification.xml: Specifically forbid empty structs (#7969) * doc/dbus-specification.xml: Patches from Kristoffer Lundén to clarify description of DBUS_COOKIE_SHA1 (#10184) and allowable contents of a variant (#10185, amended as per Havoc's comments) [All of the above are OK for MIT/X11 licensing] 2007-10-03 John (J5) Palmieri * dbus/dbus-internals.h: fd.o bug #11678 Don't error out if compiler does not support vararg macros. _dbus_verbose is the only function that does this so make it a noop if vararg macros are not supported * bus/selinux.c, dbus/dbus-sysdeps-util-unix.c: fd.o bug #12429 Reverse check to setpcap and only init audit if we were root (patch by Dan Walsh , https://bugs.freedesktop.org/show_bug.cgi?id=12429). Reverse we_were_root check to setpcap if we were root. Also only init audit if we were root. So error dbus message will not show up when policy reload happens. dbus -session will no longer try to send audit message, only system will. * configure.in: fd.o bug #11872 improve linker test for --gc-sections. Patch by Tim Mooney * configure.in, dbus/dbus-sysdeps.c: fd.o bug #11872 fix clearenv for systems that do not have it. Patch from Brian Cameron * tools/dbus-launch.c: fd.o bug #12547 remove superfluous if. Also convert tabs to spaces * configure.in, bus/Makefile.am, dbus/Makefile.am: Correctly implement -fPIC and -fPIE. For security reasons we want possition independent code for libraries and possition independent executable for executables. Before we were just enabling -fPIC. Now we correctly enable -fPIC and -PIE for libdbus and the bus respectively. Proper LD_FLAGS are set for each also. 2007-09-20 Ryan Lortie Add argument path matching support. Bug #11066. * dbus/signals.c (struct DBusMatchRule, bus_match_rule_new, bus_match_rule_set_arg, bus_match_rule_parse_arg_match, match_rule_matches): Add support for parsing and matching on arg0path='/some/path' type rules. * dbus/signals.h (bus_match_rule_set_arg): change to take const DBusString instead of const char * for the string to match against. * dbus/dbus-bus.c: add a quick note to dbus_bus_add_match documentation about the path matching. * doc/dbus-specification.xml: add a more detailed description of the changes here. 2007-09-19 Ryan Lortie Add support for compacting DBusStrings to release wasted memory. * dbus/dbus-string.[ch] (compact, _dbus_string_compact, _dbus_string_lock): new compact function to free up allocated memory that is no longer used. * dbus/dbus-message.c (load_message): call _dbus_string_compact on the message loader buffer. * dbus/dbus-transport-socket.c (do_reading, do_writing): call _dbus_string_compact on the incoming/outgoing "encoded" buffers. * dbus/dbus-string-util.c (_dbus_string_test): add a few tests for string compacting. 2007-09-13 Ryan Lortie * HACKING: add more explicit git branch/tag instructions 2007-09-13 Ryan Lortie migrate from cvs to git (cvs2svn -> git-svnimport). * HACKING: update release/branch/tag instructions * */.cvsignore: rename to .gitignore also, clean up tags and branch names to conform to HACKING 2007-08-17 William Jon McCann * update-dbus-docs.sh: upload DTD to server 2007-08-17 Havoc Pennington * tools/dbus-launch-x11.c (set_address_in_x11): fix from Michael Lorenz to use long not int with XChangeProperty format 32 * dbus/dbus-sysdeps-util-unix.c (_dbus_write_pid_to_file_and_pipe): factor this out, and use the same code in _dbus_become_daemon (where the parent writes the pid file and to the pid pipe) and in bus_context_new (where the daemon writes its own pid file and to its own pid pipe) * bus/bus.c (bus_context_new): close the pid pipe after we print to it. Also, don't write the pid to the pipe twice when we fork, someone reported this bug a long time ago. 2007-08-03 Havoc Pennington * configure.in: add major/minor/micro version number AC_SUBST * dbus/dbus-arch-deps.h.in (DBUS_MAJOR_VERSION, DBUS_MINOR_VERSION, DBUS_MICRO_VERSION, DBUS_VERSION_STRING, DBUS_VERSION): collection of macros to get version of library we are compiled against. * dbus/dbus-misc.c (dbus_get_version): new function, to get version of library we are linked against at runtime. 2007-07-30 Havoc Pennington * bus/activation-helper.c (check_bus_name): don't use _dbus_check_valid_bus_name() which is only around with --enable-checks, instead use _dbus_validate_bus_name(). Bug #11766 from Diego 2007-07-27 Havoc Pennington * configure.in: post-release version bump 2007-07-27 Havoc Pennington * release 1.1.2 2007-07-26 Havoc Pennington * bus/config-parser-trivial.c (check_return_values): disable a test that hardcoded the bus user's name * bus/dispatch.c (bus_dispatch_test_conf): remove the "if (!use_launcher)" around the tests, they were only failing because we didn't pass through all the expected errors from the helper. * bus/activation-exit-codes.h (BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED): add a code for child segfaulting (BUS_SPAWN_EXIT_CODE_GENERIC_FAILURE): make "1" be a generic failure code, so if a third party launch helper were written it could just always return 1 on failure. 2007-07-24 Daniel P. Berrange * bus/dbus-daemon.1: Add docs on new syntax options for the bus address strings * dbus/dbus-address.c: Allow * in addresses (for binding to all addresses). * dbus/dbus-sysdeps.h: * dbus/dbus-sysdeps-unix.c: Re-write to use getaddrinfo instead of gethostbyname to enable protocol independant name lookup, making IPv6 work * dbus/dbus-server-socket.h: * dbus/dbus-server-socket.c: Add support for 'family' in the address string to specify ipv4 vs ipv6. Use a port string to allow for service resolution. Allow for binding to multiple sockets at once in case of dual IPv4 & IPv6 stacks. * dbus/dbus-server-unix.c: Pass in an array of file descriptors instead of a single one. * dbus/dbus-transport-socket.h: * dbus/dbus-transport-socket.c: Add support for 'family' in the address string to specify ipv4 vs ipv6. Use a port string to allow for service resolution. 2007-07-24 Havoc Pennington * configure.in: add AM_PROG_CC_C_O to allow per-target CPPFLAGS * bus/dispatch.c (bus_dispatch_test_conf): Fix up setting TEST_LAUNCH_HELPER_CONFIG to include the full path, and enable test shell_fail_service_auto_start when use_launcher==TRUE * bus/activation-helper-bin.c (convert_error_to_exit_code): pass through the INVALID_ARGS error so the test suite works * bus/activation.c (handle_activation_exit_error): return DBUS_ERROR_NO_MEMORY if we get BUS_SPAWN_EXIT_CODE_NO_MEMORY * dbus/dbus-spawn.c (_dbus_babysitter_get_child_exit_status): return only the exit code of the child, not the entire thingy from waitpid(), and make the return value indicate whether the child exited normally (with a status code) * bus/bus.c (process_config_first_time_only): _dbus_strdup works on NULL so no need to check (process_config_every_time): move servicehelper init here, so we reload it on HUP or config file change * bus/Makefile.am (install-data-hook): remove comment because Emacs make mode seems to be grumpy about it 2007-07-24 Richard Hughes * bus/Makefile.am: * bus/test-system.c: (die), (check_memleaks), (test_pre_hook), (test_post_hook), (main): Add back the test-system.c file - not sure now this got ignored in the diff. I blame git. 2007-07-24 Richard Hughes * configure.in: Use ustar to generate the tarball; this fixes the make distcheck problem when the data files do not fit in the archive: tar: dbus-1.1.2/test/data/valid-service-files/org.freedesktop.DBus. TestSuiteShellEchoServiceFail.service.in: file name is too long (max 99); not dumped We have to have the 'long' names as the service helper matches by filename rather than by the name in the service file. 2007-07-24 Richard Hughes * configure.in: * test/Makefile.am: * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS uiteNoExec.service.in: * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS uiteNoService.service.in: * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS uiteNoUser.service.in: * test/data/valid-config-files-system/debug-allow-all-fail.conf.in: * test/data/valid-config-files-system/debug-allow-all-pass.conf.in: * test/data/valid-config-files/debug-allow-all-sha1.conf.in: * test/data/valid-config-files/debug-allow-all.conf.in: * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui teEchoService.service.in: * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui teSegfaultService.service.in: * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui teShellEchoServiceFail.service.in: * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui teShellEchoServiceSuccess.service.in: * test/data/valid-service-files/debug-echo.service.in: * test/data/valid-service-files/debug-segfault.service.in: * test/data/valid-service-files/debug-shell-echo-fail.service.in: * test/data/valid-service-files/debug-shell-echo-success.service.in: * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoS ervice.service.in: * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfa ultService.service.in: * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShell EchoServiceFail.service.in: * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShell EchoServiceSuccess.service.in: Add the data files needed by the system activation unit checks. 2007-07-24 Richard Hughes * bus/dispatch.c: (check_segfault_service_no_auto_start), (check_launch_service_file_missing), (check_launch_service_user_missing), (check_launch_service_exec_missing), (check_launch_service_service_missing), (bus_dispatch_test_conf), (bus_dispatch_test_conf_fail), (bus_dispatch_test): Add unit tests for system activation. Most are copied from the session activation tests, but some didn't apply when using a laucher. 2007-07-24 Richard Hughes * bus/activation.c: (bus_activation_activate_service): If the bus uses a service-laucher, then use the setuid laucher. 2007-07-24 Richard Hughes * configure.in: Add the needed library exports for the new laucher. 2007-07-24 Richard Hughes * configure.in: Check for -Wl,--gc-sections so we can really reduce the size of the setuid binary. 2007-07-24 Richard Hughes * bus/activation.c: (handle_activation_exit_error), (babysitter_watch_callback): Map the child exit status integer to a proper dbus error. 2007-07-24 Richard Hughes * bus/bus.c: (process_config_first_time_only), (process_config_every_time), (bus_context_unref), (bus_context_get_servicehelper): * bus/bus.h: Add the concept of a service-helper and allow it's value to be read. 2007-07-24 Richard Hughes * bus/activation.c: (bus_activation_entry_unref), (update_desktop_file_entry): Add the concept of, and read the value of user from the desktop file. The user string is not required unless we are using system activation. 2007-07-24 Richard Hughes * bus/activation.c: * bus/desktop-file.h: Move the defines into the header file, as we use these in the lauch helper as well as the desktop file parsing. 2007-07-24 Richard Hughes * bus/.cvsignore: Add the autogenerated binary files. 2007-07-24 Richard Hughes * bus/Makefile.am: * bus/test.h: Add the build glue for the lauch helper, and also add the launch-helper OOM checks into make check. I've probably broken the build, give me 2. 2007-07-24 Richard Hughes * bus/test-launch-helper.c: (die), (check_memleaks), (test_post_hook), (bus_activation_helper_oom_test), (main): Add a test wrapper to allow OOM checks on the launch helper. 2007-07-24 Richard Hughes * bus/activation-helper-bin.c: (convert_error_to_exit_code), (main): * bus/activation-helper.c: (desktop_file_for_name), (clear_environment), (check_permissions), (check_service_name), (get_parameters_for_service), (switch_user), (exec_for_correct_user), (check_bus_name), (get_correct_parser), (launch_bus_name), (check_dbus_user), (run_launch_helper): * bus/activation-helper.h: Add the initial launch-helper. This is split into a main section and a binary loader that allows us to lauch the main section in another test harness to do stuff like OOM testing. No build glue yet. 2007-07-24 Richard Hughes * bus/Makefile.am: * bus/config-parser.c: (bus_config_parser_unref), (start_busconfig_child), (bus_config_parser_end_element), (servicehelper_path), (bus_config_parser_content), (bus_config_parser_finished), (bus_config_parser_get_servicehelper), (test_default_session_servicedirs), (test_default_system_servicedirs), (bus_config_parser_test): * bus/config-parser.h: Make the config-parser code use the common config code. Also add the session and systemdirs stuff, and make the config parser aware of the servicehelper field. 2007-07-24 Richard Hughes * bus/system.conf.in: Add new servicehelper fields to the default system.conf file. 2007-07-24 Richard Hughes * bus/config-parser-trivial.c: (service_dirs_find_dir), (service_dirs_append_link_unique_or_free), (bus_config_parser_new), (bus_config_parser_unref), (bus_config_parser_start_element), (bus_config_parser_end_element), (bus_config_parser_content), (bus_config_parser_finished), (bus_config_parser_get_user), (bus_config_parser_get_type), (bus_config_parser_get_service_dirs), (check_return_values), (do_load), (check_loader_oom_func), (process_test_valid_subdir), (make_full_path), (check_file_valid), (bus_config_parser_trivial_test): * bus/config-parser-trivial.h: Add a security sensitive stripped down config parser for the setuid launcher. This file only reads what it needs, and doesn't try to do anything remotely clever like including external files. It is not intended to validate the config file; it is expected that config-parser will do that before the setuid program tries to read it. 2007-07-24 Richard Hughes * bus/config-parser-common.c: (bus_config_parser_element_name_to_type), (bus_config_parser_element_type_to_name): * bus/config-parser-common.h: We don't want to run the whole config parser with all it's deps in the setuid program. We need to implement a stripped down config parser just for the launcher, and to do so I need some common functions and defines; add them here. 2007-07-24 Richard Hughes * dbus/dbus-sysdeps-unix.c: (_dbus_get_standard_system_servicedirs): * dbus/dbus-sysdeps-win.c: Provide a way to get the standard system servicedirs, just like we do for the session service dirs. These should be seporate, as there may be a security issue starting up some session stuff as root. The use-case for the same binary starting up per-system _and_ per-session is also not valid. 2007-07-24 Richard Hughes * bus/dbus-daemon.1.in: Add standard_system_servicedirs and servicehelper into the man file and explain what each does. 2007-07-24 Richard Hughes * doc/busconfig.dtd: Add servicehelper into the dtd, it will soon be a valid part of the config file. 2007-07-24 Richard Hughes * dbus/dbus-spawn.c: (read_data), (_dbus_babysitter_get_child_exit_status): * dbus/dbus-spawn.h: Add a function so we can get access to the exit status of the launch helper. By providing the return code and not the error we can leave the 'what does this mean?' to the bus launch code and not include it in the dbus directory. 2007-07-24 Richard Hughes * bus/activation-exit-codes.h: Add defines which specify the output codes of the launch helper. We have to use exit codes as this is the only way we can return failure type without going grotty things like redirecting possibly-nonsecure stderr into the error. 2007-07-24 Richard Hughes * dbus/dbus-protocol.h: Add new error names needed for the launch helper. 2007-07-24 Richard Hughes * dbus/dbus-sysdeps.c: (_dbus_clearenv): * dbus/dbus-sysdeps.h: Add a wrapper for clearenv. 2007-07-24 Richard Hughes * doc/system-activation.txt: Add design document for the system activation parts. I'll shortly be committing many patches that add system activation using a setuid launcher into CVS, so expect things to be broken for a few hours. 2007-07-19 Ralf Habacker * cmake/modules/FindKDEWIN.cmake: fixed comment * cmake/modules/FindKDEWIN32.cmake: removed obsolate cmake module 2007-07-18 Havoc Pennington * dbus/dbus-message.c (dbus_message_get_cached) (dbus_message_cache_or_finalize): don't mess with message from message cache outside of the cache lock. Bug #9164 from Jonathan Matthew. 2007-07-13 Havoc Pennington * Add indent-tabs-mode: nil to all file headers. 2007-07-12 Havoc Pennington * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): invert the test for parsing hex as double to be sure it fails to work * dbus/dbus-sysdeps.c (_dbus_string_parse_double): don't allow hex numbers. 2007-07-10 Havoc Pennington * dbus/dbus-connection.c (struct DBusConnection): Fix from Olivier Hochreutiner to avoid trying to protect individual bits in a word with different locks (make dispatch_acquired and io_path_acquired dbus_bool_t rather than bitfields) 2007-07-09 Ralf Habacker * dbus/dbus-sysdeps-win.c,dbus-sysdeps-win.h,dbus-sysdeps-win-util.c, dbus-sysdeps-spawn-win.c: synced with windbus sources 2007-07-07 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_getsid): remove unused jump label (_dbus_read_credentials_socket): _dbus_string_init could fail, check initialisation (_dbus_get_working_dir, _dbus_init_working_dir): remove unused functions 2007-07-04 Ralf Habacker * cmake/modules/FindKDEWIN.cmake: search in \win32libs for windows supplementary packages too 2007-06-30 Ralf Habacker * cmake/dbus/CMakeLists.txt: handle userdb as unix file 2007-06-30 Ralf Habacker * dbus/dbus-sysdeps-win.c,dbus/dbus-sysdeps-win.h: removed obsolate DBusUserInfo code 2007-06-30 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_daemon_init): reduced compiler warnings 2007-06-23 Ralf Habacker * dbus/dbus-auth-script.c (_dbus_auth_script_run): added UNIX_ONLY and WIN_ONLY commands for auth scripts * test/data/auth/external-root.auth-script: limit execution to unix 2007-06-21 Havoc Pennington * dbus/dbus-tranport.c (auth_via_default_rules): made the verbose spam cross-platform 2007-06-21 Havoc Pennington * dbus/dbus-watch.c (dbus_watch_get_fd): 1) its behavior should not be the same as before, the ABI has never been declared stable on Windows and 2) do not commit to cross-platform files without posting the exact patch to the mailing list * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): as I have pointed out before, either 0xff needs to work on both platforms, or none of the dbus code can rely on it working. That means the options are 1) audit the code for anywhere that relies on 0xff working, if none found ideally add a test that it *doesn't* work and make unix reject it explicitly, but in any case this test would go away or 2) make it work on Windows also, then we don't have to figure out whether we rely on it. And in either case, post the exact patch to the mailing list and don't just commit. 2007-06-21 Ralf Habacker * cmake/CMakeLists.txt: added VERSION_PATCH to be able to distinguish win32 binary release from dbus versioning 2007-06-21 Ralf Habacker * dbus/dbus-sysdeps-win.c: deleted local DBusCredentials structure (_dbus_getsid): new function (_dbus_read_credentials_socket): used correct function (_dbus_append_user_from_current_process, _dbus_credentials_add_from_current_process): added real sid reading (_dbus_credentials_parse_and_add_desired,_dbus_parse_uid): deleted 2007-06-21 Ralf Habacker * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): don't check 0xff as floating point, this isn't supported on win32 math implementation 2007-06-21 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_homedir_from_username, _dbus_homedir_from_current_process, _dbus_append_desired_identity): removed obsolate functions 2007-06-21 Ralf Habacker * dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-util-win.c, dbus/dbus-sysdeps-win.h: disabled uid/sid conversation stuff implementation by Peter Kuemmel 2007-06-21 Ralf Habacker * dbus/dbus-watch.c (dbus_watch_get_fd): this function is deprecated and its behavior should be as before until all client code is migrated. 2007-06-19 Ralf Habacker * dbus/dbus-sysdeps-util-win.c, tools/dbus-launch-win.c: msvc7.1 fixes by Jaroslaw Staniek tested with mingw 2007-06-19 Ralf Habacker * dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-spawn-win.c, dbus/dbus-sysdeps-win.h: disabled DBusSocket implementation by Peter Kuemmel 2007-06-18 Ralf Habacker * dbus-win.patch: removed obsolate patches 2007-06-18 Havoc Pennington * configure.in: bump version to 1.1.2 so CVS is higher than last release (this is not the 1.1.2 release) 2007-06-18 Havoc Pennington * Release 1.1.1 2007-06-18 Havoc Pennington * doc/dbus-specification.xml: document org.freedesktop.DBus.GetId() * bus/driver.c (bus_driver_handle_get_id): implement org.freedesktop.DBus.GetId() * bus/bus.c (bus_context_new): generate a unique ID for each bus context * dbus/dbus-connection.c (dbus_connection_get_server_id): new function * dbus/dbus-bus.c (dbus_bus_get_id): new function * dbus/dbus-server.c (dbus_server_get_id): new function 2007-06-18 Havoc Pennington * dbus/dbus-sysdeps-unix.c (_dbus_read_credentials_socket): clean this up a little bit, to try and understand why telnet'ing to a server and sending a non-nul byte didn't disconnect immediately; now it seems that it does disconnect immediately as it should, though I don't understand what has changed. 2007-06-18 Havoc Pennington * dbus/dbus-watch.c (dbus_watch_get_socket) (dbus_watch_get_unix_fd): new API to match DBusConnection (dbus_watch_get_fd): deprecate this Throughout: just s/dbus_watch_get_fd/dbus_watch_get_socket/g for now since all the transports use sockets anyway 2007-06-16 Ralf Habacker * dbus/dbus-macros.h, dbus/dbus-message.c, dbus/dbus-message.h: renamed DBUS_GNUC_DEPRECATED to DBUS_DEPRECATED and extended to msvc compiler 2007-06-15 Ralf Habacker * cmake/CMakeLists.txt: use local include header first * dbus/dbus-sysdeps-win.c: mingw fix of DBusCredential struct 2007-06-15 Ralf Habacker * cmake/ConfigureChecks.cmake,cmake/config.h.cmake: added check for HAVE_ERRNO_H * cmake/dbus/CMakeLists.txt: added missing files * dbus/dbus-transport-win.c/.h: new files * dbus/dbus-sysdeps-win.c,.h: added required _unix functions to make dbus compilable on win32 * dbus/dbus-sysdeps-win-utils.c,.h: moved some functions to dbus-sysdeps-win.c * dbus-win.patch: removed applied or obsolate patches Note: dbus-win32 is now compilable, no guarantee that it runs without any problems 2007-06-15 Havoc Pennington * dbus/dbus-sysdeps-unix.c (_dbus_append_session_config_file) (_dbus_append_system_config_file): new functions * bus/main.c (main): use _dbus_append_system_config_file() and _dbus_append_session_config_file() * dbus/Makefile.am (INCLUDES): move DBUS_SYSTEM_CONFIG_FILE and DBUS_SESSION_CONFIG_FILE into this makefile 2007-06-15 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_set_errno_to_zero) (_dbus_get_is_errno_nonzero, _dbus_get_is_errno_eintr) (_dbus_strerror_from_errno): family of functions to abstract errno, though these are somewhat bogus (really we should make our socket wrappers not use errno probably - the issue is that any usage of errno that isn't socket-related probably is not cross-platform, so should either be in a unix-only file that can use errno directly, or is a bug - these general errno wrappers hide issues of this nature in non-socket code, while socket-specific API changes would not since sockets are allowed cross-platform) 2007-06-14 Havoc Pennington * bus/dispatch.c (check_get_connection_unix_process_id): mop up getpid() (noticed by Peter Kümmel) and adapt the test to expect a "pid unknown" error when running on Windows. 2007-06-14 Havoc Pennington * dbus/dbus-sysdeps-unix.c (_dbus_credentials_parse_and_add_user): delete this function since it was effectively the same as _dbus_credentials_add_from_username() 2007-06-14 Havoc Pennington * dbus/dbus-auth.c: adapt to keyring changes * dbus/dbus-keyring.c: change to avoid using user ID and home directory directly; instead use a keyring-location-from-credentials function in dbus-sysdeps * fix to use _dbus_append_user_from_current_process() instead of _dbus_username_from_current_process() or _dbus_append_desired_identity(). 2007-06-14 Ralf Habacker * reverted global rename of function _dbus_username_from_current_process. It needs too much tests to verify that the change does not break anything. I had overseen that the signatures are different and requires non trivial changes. This is one *major* disadvantage of emulating oop functionality with c. You are responsible for cleaning every object on every function return point which could be a nightmare if you are not working with dbus all the days. 2007-06-14 Ralf Habacker * dbus/dbus-auth.c (handle_client_initial_response_cookie_sha1_mech): fixed usage of _dbus_append_desired_identity() * dbus/dbus-sysdeps.h (_dbus_username_from_current_process): removed prototype 2007-06-14 Ralf Habacker * dbus/dbus-sysdeps.c: moved global lock system_users from dbus-userdb.c 2007-06-14 Ralf Habacker * global rename of function _dbus_username_from_current_process to _dbus_append_desired_identity. Approved by Havoc Pennington 2007-06-14 Ralf Habacker * dbus/dbus-sysdeps-win.c: disabled DBusUserInfo related code (_dbus_append_desired_identity, _dbus_windows_user_is_process_owner): new win32 functions as counterpart of unix related (_dbus_send_credentials_socket,_dbus_read_credentials_socket): renamed from ..._unix_socket (_dbus_send_credentials_unix_socket): removed obsolate function * dbus/dbus-sysdeps-win-util.c: disabled DBusGroupInfo related code (_dbus_verify_daemon_user,_dbus_change_to_daemon_user): new win32 functions as counterpart of unix related 2007-06-14 Simon McVittie * doc/dbus-specification.xml: say the protocol version is 1 instead of 0 (patch from Kristoffer Lundén, fd.o#10033) and remove the FIXME about removing protocol version from messages (as per Havoc's comment on that bug) 2007-06-14 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_pid_for_log,_dbus_flush_caches): new win32 functions as counterpart of unix related 2007-06-14 Ralf Habacker * cmake/modules/FindKDEWIN.cmake, cmake/modules/FindKDEWIN_Packager.cmake, cmake/modules/Win32Macros.cmake: new files from the kdewin32 project * cmake/CMakeLists.txt: cleaned support for kdewin installer and win32 explorer wrapper 2007-06-13 Havoc Pennington * dbus/dbus-message.c (dbus_message_iter_open_container): Fix broken return_if_fail (kind of scary that test suite does not cover this) 2007-06-13 Havoc Pennington * dbus/dbus-server-socket.c (_dbus_server_listen_socket): support all_interfaces=true|false for tcp servers * dbus/dbus-sysdeps-unix.c (_dbus_listen_tcp_socket): support inaddr_any flag * bus/selinux.c: fix some missing includes * dbus/dbus-server-socket.c (_dbus_server_listen_socket): allow port to simply be omitted in addition to specifying 0 2007-06-13 Havoc Pennington * configure.ac, bus/selinux.c, dbus/dbus-sysdeps-unix-util.c: add libaudit support, no clue what this means really but now we have it. Patches from Fedora package. * bus/bus.c (bus_context_new): move selinux initialization after changing to daemon user, patch from Fedora package * dbus/dbus-transport.c (auth_via_unix_user_function): fix a typo 2007-06-12 Havoc Pennington * dbus/dbus-message.c (dbus_message_iter_open_container): improve the checks/warnings for contained_signature a bit 2007-06-12 Havoc Pennington * dbus/dbus-marshal-recursive.c (write_or_verify_typecode): improve the warning a bit if you write extra data into a message 2007-06-12 Havoc Pennington * dbus/dbus-auth.c (sha1_handle_second_client_response) (handle_server_data_anonymous_mech): add the process ID from socket credentials, if available, even if not using EXTERNAL * dbus/dbus-transport.c (auth_via_default_rules): support allow_anonymous flag * dbus/dbus-connection.c (dbus_connection_get_is_anonymous) (dbus_connection_set_allow_anonymous): new API for controlling anonymous access 2007-06-09 Havoc Pennington * dbus/dbus-string.c (_dbus_string_pop_line): fix this not to think an empty line is the end of the file. Also, fix some whitespace. * dbus/dbus-string-util.c: add more tests for _dbus_string_pop_line() revealing that it thinks an empty line is the end of the file, which broke dbus-auth-script.c so it didn't really run the scripts * dbus/dbus-auth.c: add ANONYMOUS mechanism * dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect an empty/no-op auth script; add commands to check that we have or don't have the expected credentials 2007-06-09 Havoc Pennington * bus/policy.c (bus_policy_create_client_policy): gracefully continue if the connection has no unix user - just don't apply any unix user dependent rules. * bus/config-parser.c: remove dbus-userdb.h usage * bus/bus.c: remove dbus-userdb.h usage * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): support Windows user function; also, fix the logic for checking auth as root in the default auth code (broken in the previous commit) * dbus/dbus-connection.c (dbus_connection_set_windows_user_function): new function (dbus_connection_get_windows_user): new function 2007-06-09 Havoc Pennington * bus/dispatch.c (check_get_connection_unix_process_id): adapt since sysdeps-unix.h stuff isn't included anymore * bus/bus.c (bus_context_new): use more abstract functions to change user, so they can be no-ops on Windows * dbus/dbus-credentials.c, dbus/dbus-credentials.h, dbus/dbus-credentials-util.c: new files containing a fully opaque DBusCredentials data type to replace the old not opaque one. * configure.in (DBUS_UNIX): define DBUS_UNIX to match DBUS_WIN on windows * dbus/dbus-userdb.h: prohibit on Windows, next step is to clean up the uses of it in bus/*.c and factor out the parts of cookie auth that depend on it 2007-06-07 Havoc Pennington * dbus/dbus-message.c: improve some docs related to reading values from a message iter 2007-06-02 Ralf Habacker * cmake: added cygwin compile support 2007-06-01 Ralf Habacker * tools/dbus-launch-win.c: new file, replaces script wrapper on win32. * cmake/dbus-launch.bat.cmake: removed obsolate file 2007-05-31 Ralf Habacker * bus/main.c (main): uses _dbus_get_config_file_name() to detect session.conf location on win32. * dbus-sysdeps-win.h (_dbus_get_config_file_name,_dbus_file_exists): new prototyp, undefined interface after including windows.h because it makes trouble when a paramater is named interface. * dbus-sysdeps-win.c (_dbus_get_install_root, _dbus_get_config_file_name,_dbus_file_exists): new functions. 2007-05-27 Ralf Habacker * bus/policy.c,dbus/dbus-internals.c: fixed inconsistant line endings as reported by Peter Kümmel. 2007-05-25 John (J5) Palmieri * Released 1.1.0 2007-05-25 John (J5) Palmieri * Split NEWS and ChangeLog into a .pre-1-0 file as per HACKING We forgot to do this during the 1.0 release and it makes sense now as we get ready to release the first 1.1.0 development tarball 2007-05-25 John (J5) Palmieri * create directory test/data/valid-config-files/session.d so that make check passes 2007-05-25 John (J5) Palmieri * INSTALL: remove dependancies for bindings since they no longer are a part of core 2007-05-25 Ralf Habacker * dbus/dbus-server-win.c,dbus/dbus-server-win.h: new file with empty function _dbus_server_listen_platform_specific(). * dbus/dbus-server.c (listen_funcs): uses _dbus_server_listen_platform_specific on any platform. 2007-05-25 Ralf Habacker * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): not getting user info from a domain controller isn't an error, the computer may run in a non domain context. 2007-05-25 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_full_duplex_pipe): fixed assertation. 2007-05-24 Simon McVittie * bus/config-parser.c (test_service_dir_matches): fixed ordering for unix. * bus/config-parser.c (test_default_session_servicedirs): made allocation of _progs platform independent. 2007-05-23 Havoc Pennington * bus/Makefile.am (install-data-hook): create session.d * bus/session.conf.in: add session.d for the session bus, so security policy can be extended 2007-05-22 Ralf.Habacker * cmake/CMakeLists.txt: fixed creating of TEST_..._BINARY to make bus-test able to find the binaries. 2007-05-21 Simon McVittie * acinclude.m4, configure.in: In recent autotools, ${datadir} is defined in terms of ${datarootdir}, so EXPANDED_DATADIR needs to be expanded recursively. Rather than fixing configure.in to do this, I grabbed the AS_AC_EXPAND macro from autostars.sf.net, which seems to be commonly used. 2007-05-21 Simon McVittie * update-dbus-docs.sh: Assorted improvements: - Default user if $FDUSER is not set is the ssh default (set in ~/.ssh/config or based on the local username), not a hard-coded "johnp" - Temporary checkout directory is created securely (preventing symlink attacks), if mktemp(1) is available - Use make -C rather than cd && make && cd .. 2007-05-21 Simon McVittie * HACKING: Point to correct mailing list 2007-05-21 Simon McVittie * doc/dbus-specification.xml: explicitly specify that STRING cannot contain embedded NULs. 2007-05-20 Ralf.Habacker * dbus/dbus-internal.c: fix inline problem on win32. 2007-05-20 Ralf.Habacker * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): not reaching domain controller isn't an error, converted error message to verbose message. 2007-05-19 Ralf.Habacker * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): disabled tests not running on wince. 2007-05-19 Ralf.Habacker * dbus/dbus-internals.c (_dbus_verbose_init): win32 requires 'varname=' to unset a environment variable. 2007-05-19 Ralf.Habacker * dbus/dbus-sysdeps.c (_dbus_setenv): win32 requires 'varname=' to unset a environment variable. 2007-05-19 Ralf.Habacker * bus/policy.c (bus_policy_create_client_policy): win32 temporary fix until the userdb stuff is ported completly. 2007-05-19 Ralf.Habacker * dbus/dbus-server.c (listen_funcs): _dbus_server_listen_platform_specific is empty on win32, limited to unix only. * dbus/dbus-server.c (valid_addresses): limit unix only addresses to unix. 2007-05-18 Havoc Pennington * doc/dbus-specification.xml: add a GetAll to the Properties interface. 2007-05-17 Ralf.Habacker * bus\config-parser.c (test_default_session_servicedirs): win32 fix. 2007-05-17 Ralf.Habacker * configure.in: define constant DBUS_UNIX. 2007-05-14 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_printf_string_upper_bound): compile fix for MS Platform SDK 6 patch from Michael Luschas 2007-05-10 John (J5) Palmieri * dbus-1.pc.in: add daemondir to pc file patch from Brian Cameron 2007-05-04 Simon McVittie * doc/dbus-specification.xml: mention the reserved o.fd.DBus.Local interface and the corresponding /o/fd/DBus/Local object path; describe them as reserved and forbid using them in a sent message, mentioning that in the reference implementation this will cause the connection to be dropped. Patch approved by Havoc. 2007-04-28 Ralf Habacker * cmake/: don't install test applications and service files, moved CMAKE_DEBUG_POSTFIX to top level CMakeLists.txt 2007-04-27 Havoc Pennington * dbus/dbus-sysdeps-unix.c (_dbus_open_socket): fix #10781 from Tobias Nygren, checking pointer to fd vs. 0 rather than checking the fd itself 2007-04-26 Ralf Habacker * cmake/: added debug postfixes to debug exe's for easier debugging. * dbus\dbus-sysdeps-win.c (_dbus_win_set_error_from_win_error): print error code in case no string message is available. 2007-04-06 Simon McVittie * dbus/dbus-message-util.c, dbus/dbus-message.c, dbus/dbus-message.h: Add API to convert a DBusMessage to/from a byte array. Patch from Dafydd Harries , approved by Havoc Pennington. 2007-04-03 Timo Hoenig * dbus/dbus-address.c (dbus_parse_address): Do not accept zero- length address. * dbus/dbus-address.c (_dbus_address_test): Add test for zero- length address. 2007-03-25 Ralf.Habacker * cmake/dbus/CMakeLists.txt: debug postfix also for mingw. 2007-03-16 Ralf.Habacker * cmake/modules/FindExpat.cmake: fix package detection on win32. * README.win: update install instructions. 2007-03-16 Ralf.Habacker * dbus/dbus-sysdeps.h (_dbus_split_paths_and_append): new prototyp (_DBUS_PATH_SEPARATOR): new macro. * dbus/dbus-sysdeps.c (_dbus_split_paths_and_append): merged from dbus/dbus-sysdeps-unix.c and dbus/dbus-sysdeps-win.c. 2007-03-15 Ralf.Habacker * bus/config-parser.c, bus/policy.c, bus/policy.h, bus/dbus-daemon.1.in, bus/session.conf.in: added eavesdrop support for replies - patch by olli.salli at collabora.co.uk approved by Havoc Pennington. 2007-03-15 Ralf.Habacker * dbus\dbus-sysdeps-win-thread.c: renamed to dbus-sysdeps-thread-win.c, it is a platform depending file similar to dbus-sysdeps-pthread.c. 2007-03-15 Ralf.Habacker * cmake\doc\CMakeLists.txt: added prelimary xml doc support, needs cmake Find script. 2007-03-14 Ralf.Habacker * cmake: add doxygen support 2007-03-14 Ralf.Habacker * cmake/config.h.cmake: WINCE fixes, defined DBUS_UNIX. 2007-03-13 Ralf.Habacker * dbus/dbus-sysdeps-util-win.c (dbus_become_daemon): win32 compile fix. 2007-03-13 Ralf.Habacker * dbus-win.patch: removed obsolate patches. 2007-03-13 Ralf.Habacker * dbus/dbus-sysdeps-win.c: added zero byte sending and receiving after connection start up 2007-03-11 Havoc Pennington * tools/dbus-launch.c (do_close_stderr): fix C89 problem and formatting problem * Mostly fix the DBusPipe mess. - put line break after function return types - put space before parens - do not pass structs around by value - don't use dbus_strerror after calling supposedly cross-platform api - don't name pipe variables "fd" - abstract special fd numbers like -1 and 1 2007-03-12 Ralf Habacker * dbus/dbus-sysdeps-win.h, dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-util-win.c: renamed functions _dbus_xxx_file() to _dbus_file_xxx() to reflect struct name DBusFile. 2007-03-12 Ralf Habacker * dbus/dbus-sysdeps-util-unix.c (_dbus_become_daemon): fix _dbus_pid_fd check. 2007-03-10 Ralf Habacker * tools/dbus-print-message.c (print_message): added printing of the reply serial to method returns and errors, so you can actually figure out the message/reply pairs - patch by olli.salli at collabora.co.uk. 2007-03-10 Ralf Habacker * dbus-win.patch: removed committed patches. 2007-03-10 Ralf Habacker * bus/bus.c, bus/bus.h, bus/main.c, bus/test.c, dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps-util-unix.c, dbus/dbus-sysdeps-util-win.c, dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps.h: renamed _dbus_xxx_pipe to _dbus_pipe_xxx, completed _dbus_pipe support. 2007-03-10 Ralf Habacker * dbus/dbus-sysdeps.h (_dbus_listen_tcp_socket): changed type or port to pointer, because the port is given back. * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): implemented returning tcp port. Skipping port parameter and non integer port values in config statement needs more effort. * dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps-win.c (_dbus_listen_tcp_socket): return the real used tcp port. * bus/dbus-daemon.1.in: added tcp examples 2007-03-09 Ralf Habacker * cmake/config.h.cmake: win32 msvc bug fix 2007-03-09 Ralf Habacker * cmake/config.h.cmake: fixed DBUS_WINxx defines, using _WINCE does not work. 2007-03-08 Ralf Habacker * dbus-win.patch: removed _dbus_write_pipe() patch, it is now committed. 2007-03-08 Ralf Habacker * bus/bus.c, dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps.h: rename pipe related write() function calls to _dbus_write_pipe(). 2007-03-08 Ralf Habacker * dbus-win.patch: added bus/config-loader-libexpat.c patch, uses DBUS_WIN for alls win32 related #ifdefs, some minor cleanups 2007-03-08 Ralf Habacker * dbus-win.patch: updated patch for bus/dispatch.c. 2007-03-08 Ralf Habacker * dbus-win.patch: dbus-connection.c (dbus_connection_get_unix_user, dbus_connection_get_unix_process_id): Let return them valid user id's, otherwise bus-test fails. How to replace on win32 ?. * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): fix memory leak. 2007-03-08 Ralf Habacker * dbus/dbus-sysdeps-win.c (_dbus_win_set_error_from_win_error): use dbus friendly error name. (fill_win_user_info_homedir): print user name in error case too. 2007-03-08 Ralf Habacker * cmake/ConfigureChecks.cmake: fixed socketpair check 2007-03-08 Ralf Habacker * bus/dispatch.c: disabled segfault test on win32 for now 2007-03-08 Ralf Habacker * configure.in, cmake/ConfigureChecks.cmake: added check for setrlimit. * test/test-segfault.c: only include setrlimit stuff only when available. 2007-03-07 Ralf Habacker * test/test-segfault.c: unix compile fix. * dbus-win.patch: removed obsolate patches. 2007-03-07 Ralf Habacker * bus/activation.c: removed obsolate include header. * test/test-segfault.c: win32 compile fix, rlimit isn't available on win32. * dbus-win.patch: removed some more patches, they are applied or obsolate 2007-03-06 Ralf Habacker * bus-win.patch: fixes unix listen problems, dbus-test now runs. 2007-03-06 Ralf Habacker * cmake/dbus/CMakeLists.txt,cmake/bus/CMakeLists.txt, cmake/CMakeLists.txt: win32 compile fix 2007-03-04 Ralf Habacker * dbus-win.patch, README.win: added available win32 patches from windbus project (http://sf.net/projects/windbus) 2007-03-04 Ralf Habacker * bus/activation.c: (bus_activation_activate_service): fixed call to _dbus_spawn_async_with_babysitter(). 2007-03-04 Ralf Habacker * dbus/dbus-spawn.c,dbus/dbus-spawn.h (_dbus_spawn_async_with_babysitter): added environment pointer as function parameter, used on win32. * test/spawn-test.c: fixed call to above mentioned function. 2007-03-04 Ralf Habacker * configure.in,test/test-sleep-forever.c,test/test-names.c: added configure check for unistd.h. 2007-03-04 Ralf Habacker * test/Makefile.am: fixed test data copy problem in out of source build, when sources came from svn or cvs. 2007-03-03 Ralf Habacker * dbus/*-win.*,bus/*-win.*: added win32 platform related files. These files are only added to the cmake build system. The missing dbus-win.patch file will be added later. 2007-03-03 Ralf Habacker * cmake: new directory, contains cmake build support. See http://www.cmake.org for more informations. Currently only unix will be buildable because some win32 required files are still missing. 2007-03-03 Thiago Macieira * dbus/dbus-sysdeps-unix.c: capture the dbus-launch stderr output and add it to the DBusError message we return. * tools/dbus-launch.1: * tools/dbus-launch.c: Add option --close-stderr to, well, close stderr before starting dbus-daemon. 2007-01-31 Havoc Pennington * bus/dbus-daemon.1.in: write a section in the man page on running a test daemon for debugging purposes 2007-01-26 Havoc Pennington * bus/session.conf.in: override all the default limits with much higher limits on the session bus, there is no reason the session bus should have low limits * bus/config-parser.c (bus_config_parser_new): increase default limits so they are less likely to be hit; in particular the max replies per connection was way too low 2006-01-25 Simon McVittie * doc/dbus-tutorial.xml: Replace Python section of tutorial with a pointer to the tutorial maintained as part of dbus-python 2006-12-31 Ralf Habacker * dbus/dbus-sysdeps-unix.c: unix compile fix, moved atomic_exchange_and_add() from dbus/dbus-sysdeps.c to here, it's used by _dbus_atomic_inc() and _dbus_atomic_dec(). 2006-12-31 Ralf Habacker * tools/dbus-monitor.c: gettimeofday() is not available on windows so we have to provide our own. It's taken from lgpl'd kdewin32 package. - Patches from Christian Ehrlicher 2006-12-31 Ralf Habacker * dbus/dbus-sysdeps-unix.c: moved _dbus_atomic_inc/dec() from dbus/dbus-sysdeps.c, windows version of _dbus_atomic_inc/dec() is in dbus-sysdeps-win.c (not in this patch). * dbus/dbus-sysdeps.h: DBusAtomic::value is long on windows to fit with InterlockedInc/Decrement. - Patches from Christian Ehrlicher 2006-12-31 Ralf Habacker * tools/dbus-send.c, tools/dbus-monitor.c: win32 compile fix. 2006-12-31 Ralf Habacker * dbus/dbus-marshal-recursive.c (type DBusTypeReaderClass): fix mispaced const statement. - Patch from Peter Kümmel 2006-12-19 Ray Strode * bus/bus.c (process_config_every_time): don't overwrite existing bus context activation object until after we've checked that the new activation is valid. * bus/main.c (signal_handler), (handle_reload_watch): don't call exit() on failure, instead make do and keep going. (close_reload_pipe): new function to turn off hangup-causes-config-reload behavior if an unexpected error occurs 2006-12-13 Ralf Habacker * dbus/dbus-sysdeps-win-thread.c (_dbus_condvar_wait_win32): correctness fix. - Patch from Christian Ehrlicher 2006-12-13 Ralf Habacker * dbus/dbus-internals.h: msvc also knows about __FUNCTION__, we should also use it. - Patch from Christian Ehrlicher 2006-12-13 Ralf Habacker * dbus-sysdeps-util.c: added win32 related tests 2006-12-12 Ralf Habacker * dbus/dbus-string.c (_dbus_string_pop_line), bus/desktop-file.c (parse_section_start, parse_comment_or_blank,parse_key_value,): uses _dbus_string_find_eol() to support platform independent eol style. 2006-12-12 Ralf Habacker * dbus/dbus-string.[ch] (_dbus_string_find_eol): new function. * dbus/dbus-string-util.c (_dbus_string_test): added testcases for _dbus_string_find_eol(). Approved by: Havoc Pennington. 2006-12-12 Tim Dijkstra * configure.in: Added switch to disable user_database caching. * dbus/dbus-userdb-util.c, dbus/dbus-userdb.c: Add ifdefs to be able disable user_dabase caching. 2006-12-12 Tim Dijkstra * bus/bus.c, bus/bus.h: Remove DBusUserDatabase from the BusContext struct. It is unnecessary we have a global one already. Also remove bus_context_get_user_database function, it is no longer needed. Flush the global database on reload. * dbus/dbus-userdb-util.c: Replace _dbus_user_database_get_groups with _dbus_groups_from_uid. It no longer needs a DBusUserDatabase. * dbus/dbus-userdb.c, dbus/dbus-userdb.h: Add _dbus_user_database_flush_system. Make more functions DBUS_USERDB_INCLUDES_PRIVATE. Small unrelated change in _dbus_is_a_number: change _dbus_string_parse_int to _dbus_string_parse_uint. * bus/connection.c: Change call to _dbus_user_database_get_groups to _dbus_groups_from_uid. * bus/policy.c, bus/policy.h: Change call to _dbus_user_database_get_groups to _dbus_groups_from_uid. Remove DBusUserDatabase from bus_policy_allow_user prototype, it no longer needs it. 2006-12-12 John (J5) Palmieri * bus/signal.c: Fix match_rule_equal errata (CVE-2006-6107 - Patch from Kimmo Hämäläinen ) 2006-11-19 Thiago Macieira * dbus/dbus-sysdeps-pthread.c (_dbus_pthread_mutex_lock, _dbus_pthread_condvar_wait, _dbus_pthread_condvar_wait_timeout): set pmutex->holder to pthread_self() after coming back from a conditional variable wait as well as in one codepath where it was forgotten. Approved by: Havoc Pennington. 2006-11-17 Havoc Pennington * update-dbus-docs.sh: allow setting fd.org username via env variable. Make it run autogen with --enable-xml-docs=yes --enable-doxygen-docs=yes so configure will fail if the required tools are missing. 2006-11-17 Havoc Pennington * doc/dbus-faq.xml: minor FAQ tweaks 2006-11-14 Havoc Pennington * dbus/dbus-misc.c, dbus/dbus-misc.h: Move dbus_get_local_machine_id() to its own file, no substantive changes. There are a couple other things we might want to add that are "misc" so moving out of dbus-connection.[hc] which is big enough already. 2006-11-14 Havoc Pennington * dbus/dbus-internals.c (_dbus_generate_uuid): The spec said the UUID had the timestamp last, but the implementation had it first; move it to last since I think it's a tiny bit nicer (easier to compare at a glance, faster to sort, less code), and will not cause any practical compatibility problems. Also, always convert the timestamp to big endian. * doc/dbus-specification.xml: Clean up the docs on the UUID. * tools/dbus-uuidgen.1: more prominently say it is not suitable as a replacement for regular uuidgen/RFC4122. 2006-11-14 John (J5) Palmieri * dbus/dbus-threads.h: fix DBUS_THREAD_FUNCTIONS_ALL_MASK to have the correct value so we don't assert when initalizing recursive threads * test/name-test/test-thread-init.c: call dbus_threads_init_default instead of _dbus_threads_init_debug since it is more of a real world test dbus-1.10.6/NEWS.pre-1-00000644000175000017500000005430112602773110014317 0ustar00smcvsmcv00000000000000D-Bus 1.0.0 (08 November 2006) == - Documents updated with API/ABI garuntees - Added missing patch FreeBSD need to run out of the box - dbus-monitor now has a profile mode - AUTHORS file updated with names from the ChangeLog Thanks to everyone who helped get us here D-Bus 1.0 RC 3 (0.95) (02 November 2006) == - DBUS_API_SUBJECT_TO_CHANGE no longer needs to be defined when building apps - ./configure checks now work when cross compiling - dbus-uuidgen --ensure is now run in the init script so there is no need to run it in a post script - dbus-uuidgen now writes out to /var/lib/dbus to work with systems that do not have a writable /etc. Packages should install and own the /var/lib/dbus directory - recursive locks are now used when dbus_threads_init_default is called - standard_session_servicedirs tag added to the session.conf under a normal build this specifies these service directories: /usr/local/share/dbus-1/services /usr/share/dbus-1/services $HOME/.local/share/dbus-1/services - fixed crash when a service directory is specified more than once - fixed a crash in *BSD when watching config directories for changes - fixed Irix build by using dirp->__dd_fd to get the file descriptor - cleaned up the LOCAL_CREDS vs CMGCRED credential code so *BSD's don't crash here anymore - dbus_message_iter_get_array_len deprecated - cleanup-man-pages.sh added so packagers can clean up Doxygen man page output from 7 to 2 megs - large documentation improvements - numerous bug fixes D-Bus 1.0 RC 2 (0.94) (14 October 2006) == - dbus-uuidgen binary added for future remote machine identification packagers should call dbus-uuidgen --ensure in their post - GetMachineId peer method added to the bus API - dbus_connection_set_route_peer_messages API added to let the bus send peer messages directly to an app - Autolaunch abilities added to dbus-launch with the --autolaunch flag This feature allows libdbus to start a session bus if none can be found This is an internal feature and should not be used by scripts DBUS_SESSION_BUS_ADDRESS is still the correct way to specify a session bus - dbus-launch now prints out a simple key value pairs instead of shell scripts if one of the shell flags aren't used - support DBUS_BLOCK_ON_ABORT env variable to cause blocking waiting for gdb - weak ref are now held for shared connections so the right things happen this fixes some pretty major bugs with the way connections were handled - Some refactoring for Windows (doesn't effect Unix) - Solaris build fixes - MacOSX build fixes - Cross compile build fixes. We now assume getpwnam_r is posix and va_lists can be copied by value since we can't check this in a cross compile. If this is not true for a particular target is up to the developer to patch. - Bug fixing all around D-Bus 1.0 RC 1 (0.93) (14 September 2006) == - dbus_threads_init_default added for initalizing threads without the need for bindings - Filters are now properly removed - dbus_connection_open now holds a hard ref to shared connections - We now print out a warning and do nothing when someone tries to close a shared connection - The --introspect switch has been added to the bus for printing out introspection data without actually running the bus - LOCAL_CREDS socket credentials are now supported for systems which support it such as NetBSD - Generalize kqueue support so it works with NetBSD as well as FreeBSD - Numerous bug fixes and memory leaks patched D-Bus 0.92 (18 August 2006) == - Proper thread locking added to pending calls - Threading semantics changed from init early to init before the second thread is started - Correctly error out when an application tries to acquire or release the org.freedesktop.DBus name instead of sending false result codes - kqueue directory watching code can now be used to monitor config file changes on FreeBSD - --with-dbus-daemondir configure switch added so the daemon can be installed separate from the user binaries - Makefiles fixed for cygwin - Various fixes for the ongoing Windows port - Fixed docs and comments to use the D-Bus spelling instead of D-BUS - Many memleaks and bugs fixed D-Bus 0.91 (24 July 2006) == - Remove some lingering bits left over from the bindings split - Fix assertion causing D-Bus applications to crash when checks are enabled - Fix a timeout bug which would block applications from being auto started D-Bus 0.90 (17 July 2006) == - API/ABI freeze for 1.0 - Bindings are now split out into seperate packages - ListActivatableNames added as a method on the bus - Removed deprecated dbus_connection_disconnect (use dbus_connection_close) - Shared connections are now unreffed on disconnect - Fixed pending calls for threaded enviornments - Pending calls get timed out on connection disconnect - dbus_connection_send_with_reply returns TRUE and a NULL pending call if you call it on a connection object which has been disconnected already (it returns FALSE on Out of Memory errors only) - dbus-monitor now correctly catches methods, not just signals - dbus-monitor now prints object paths D-BUS 0.62 (12 June 2006) == - Doc fixes - Added support for all data-types for the dbus tools - Fixed eavesdropping on method calls (dbus-monitor) - Fixed silent dropping of method calls with interface=NULL - Fixed console ownership problems in Solaris - Fixed installation of dbus-signature.h and #include it in dbus/dbus.h - Flush the user database cache on config reload - GLib bindings: - Fix memory leaks - Fix properties in DBusGProxy so that they can be given in any order - Added lots of assertions to ensure correct use - Remove duplicated code - Fix static string pointer uses in GPtrArray-based collections - Python bindings: - Remove reference to sys/cdefs.h - Qt4 bindings: - Code reorganized - Added the dbusidl2cpp, dbuscpp2xml and dbus tools - Added example programs (ping-pong, complex ping-pong, listnames, chat) - Updated selftests - Fixed compilation and .moc- and .ui-file processing and cleaning - Made central classes derive from QObject - Enhance error reporting - Many bugfixes - Mono bindings: - Minor bugfixes D-BUS 0.61 (24 Febuary 2006) == - Documentation all around - dbus-launch now produces correct sh and csh syntax - Nested arrays now work correctly - GLib bindings: - Inheriting from DBusGProxy is now possible - GPtrArrays can now be marshalled - org.freedesktop.DBus.GLib.ClientCSymbol annotation added - Openning connections to arbitrary addresses now supported - Python bindings: - sender_keyword and path_keyword keywords added to signal listener API - Byte types now demarshal to unsigned char - calling methods now do the correct thing - Qt bindings: - both Qt3 and Qt4 bindings can be built at the same time - Use the standard org.freedesktop.DBus.Method.NoReply annotation for the "async" calls instead of creating one for us. - Mono bindings: - 64bit arch fixes - Massive bug fixing all around D-BUS 0.60 (30 November 2005) == - major ABI/API changes - sonames changed - RequestName queuing behavior has changed (refer to dbus-specification) - DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT has been removed and DBUS_NAME_FLAG_ALLOW_REPLACEMENT has been added to the flags - signals emitted by the bus now show up in the introspect data - auth EXTERNAL now supported on BSD varients - ReleaseName method added to the bus to allow a service to remove itself as owner of a bus name - dbus_connection_read_write added for getting messages off the bus in the absence of a mainloop - Qt4 bindings added and the Qt3 bindings have been depricated - python bindings: - marshal using introspect data if available - better exception handling and propigation - private connections are now supported - UTF-8 cleanups - out_signature added to method decorators for specifying how the return values should be marshaled - sender_keyword added to method decorators for specifying and argument to provide the unique name of the method caller - async_callbacks added to method decorators - multiple inheritance of classes now supported - GLib bindings: - respect NoReply annotations - dbus_g_method_return_get_reply and dbus_g_method_return_send_reply added to the lowlevel code for use when the dbus-glib marshalling code is not adiquate - numerous bug fixes all around D-BUS 0.50 (06 September 2005) === This is a minor release from 0.36.2. The series number has changed not because of any technical reasons but as an indication that we are moving closer to 1.0. It is hoped that this will be the last series to see major changes, most of which will be isolated to the GLib and Python bindings, as we transition to concentrate more on bug busting and code auditing. - D-Bus builds on the Cygwin platform - Makefile cleanups - Various bug fixes - Optimization of the dbus object tree - Memleaks and GIL crasher bugs have been fixed in the Python bindings D-BUS 0.36.2 (29 August 2005) === - Security: Restrict other users from connecting to another users session bus D-BUS 0.36.1 (24 August 2005) === - Python Bindings: - fixed to work with hal-device-manager - For 64bit builds everything is installed to lib64/python2.4/ since Python can't handle multilib D-BUS 0.36 (23 August 2005) === - Maximum sized of cached messages have been reduced to 10K - Match rules now allow matching on arguments inside the message - introspect.xsl XSLT style sheet added for formatting introspection data into XHTML for analysis - Python bindings: - now have working type objects for explicit typecasting - Variant type has been added - Dictionaries, Variants and Arrays can all be passed the signiture or type(s) of their children - the optional timeout= keyword has been added when making method calls - match on args has been implemented - a .pth file has been added for dealing with libraries and python files being in different directories such as in 64bit installs - various bug fixes - GLib bindings: - deeply recursive types now supported - many symbols are no longer exported as part of the public API - various memleak and other bug fixes D-BUS 0.35.2 (17 July 2005) === - Rename Unix Security Context to SELinux Security Context in API - Fixed more dist errors that distcheck didn't pick up on - Fixed various bugs in the python bindings that prevented them from working D-BUS 0.35.1 (16 July 2005) === - Fixed dist error where python/dbus_bindings.pxd was being shipped instead of dbus_bindings.pxd.in - Use this instead of the 0.35 tarball D-BUS 0.35 (15 July 2005) === - --with-dbus-user added to the configure scripts for configuring the user the system bus runs on - --with-console-auth-dir added to configure scripts for configuring the directory to look in for console user locks - service files for auto-starting D-Bus services now has the ability to pass in command line arguments to the executable - Huge auto-start bug squashed which caused some services not to start when requested in rapid succession - SE-Linux security contexts can now be appended to messages for inspection by services that enforce their own security policies - Colin says the GLib binding are ready for general consumption - New GLib tutorial - New GLib example code - Python bindings are now version (0,42,0) - Python bindings API has changed on the service side - dbus.service has been split out as a seperate module - dbus.service.Service is renamed to dbus.service.BusName - dbus.service.Object has swapped the bus_name and object_path constructor parameters to make it easier to do inheritance over the bus - dbus.glib has been seperated out in order to lessen the dependency on glib and to allow other mainloops to be integrated with the bindings including a planned generic mainloop for non-gui apps. - Python bindings now aquire the GIL when calling back into the python interpreter. Fixes crashes when using threading and other random segfaults. - New Python tutorial - Numerous D-Bus bug fixes all around D-BUS 0.34 (15 June 2005) === - dbus_connection_disconnect is deprecated in favor of dbus_connection_close - The bus can now use D_NOTIFY (if available) to check when configuration files have changed and reload them - New dbus_message_has_path/member/interface API added - The Ping message from the org.freedesktop.DBus.Peer interface is now handled - Complete glib bindings overhaul (and are still under construction) - Tutorial now has an updated GLib section - GLib bindings can now send/receive hash tables, arrays and other complex types - Python bindings overhaul (most public facing API's done) - Python bindings have been split up into separate files - Python added new type classes for hinting to the marshaler what type to send over the wire - Python bindings now have decorators for specifying exported methods and signals - Numerous bug fixes D-BUS 0.33 (25 Apr 2005) === - downgrade requirement from GTK+-2.6 to 2.4 for building gtk components - python binding API's have been overhalled to be more "pythonic" and cleaner - python bindings now export dbus.version which is set to (0,40,0) - python bindings now implement the org.freedesktop.DBus.Introspectable interface - python binding match rules are now more flexable - make check has been fixed - many, many major bug fixes D-BUS 0.32 (29 Mar 2005) === - mono bindings now compiles correctly - mono binding cleanups - glib bindings generates wrappers for bus methods in dbus-glib-bindings.h - glib binding cleanus - users and groups can now be specified by UID and GID in config files - numerous memory leak fixes - various other fixes D-BUS 0.31 (07 Mar 2005) === - land the new message args API and recursive type system - add docs and fixed Doxygen warnings throught source - split out some functions not needed in libdbus to *-util.c source files - take out type convienience functions - libdbus now back below 150K - booleans are now 32-bit instead of 8-bit - specification updated - grand renaming to strip out the use of "service" just say "name" instead (or "bus name" when ambiguous) - rename dbus-daemon-1 to dbus-daemon throughout - rename activation to auto-start - auto-start on by default now - note that libdbus is the low-level API - python bindings updated to the new API - mono bindings updated to the new API - add 16 bit types - dictionaries are now ARRAYS of DICT_ENTRY - dbus-glib-tool renamed to dbus-binding-tool - massive rewrite of the glib bindings - saner names for the dbus interface, object path and service defines - new functions for handling type signitures - bump sonames for libdbus and libdbus-glib - various small fixes D-BUS 0.23 (11 Jan 2005) === - add setgroups() to drop supplementary groups - updated SELinux support - add an "at console" security policy - fix a bug where org.freedesktop.DBus wasn't recognized as an existing service. - error out if --enable-mono is explicitly set and mono libs can't be found - set the max_match_rules_per_connection limit from the config file. - removed dbus_bug_get_with_g_main since it's been replaced by dbus_g_bus_get - fix fd leaks in socket code - lots and lots of mono binding updates, including fixes to make it compatible with Mono 1.1.3 - added --nofork option to override config file setting at runtime - added support for int64 and uint64 to the python bindings - lots of python binding updates - config file DTD updates - use SerivceOwnerChanges signal instead of ServiceCreated and ServiceDeleted - fixes to the authentication code - new init script for Slackware - print out the pid even when --fork is passed - increase preallocation sizes in DBusMessage to heavily reduce reallocs - lots of performance enhancements - lots more small bug fixes D-BUS 0.22 === - add --reply-timeout to dbus-send - fix a memleak - fix Solaris/Forte build - switch to AFL 2.1 rather than 2.0 to address patent termination clause concerns - add SELinux support - mostly repair libxml backend for config parser, still doesn't pass out of memory tests - fix distcheck to include language bindings - add GetConnectionUnixUser method on bus driver - also for UnixProcessID - lots of Python, Mono, other binding fixes - change GLib bindings to not include dbus/dbus.h (fully encapsulate libdbus) - pass paths as strings, not arrays of string - add message signature header field - cleanups to marshaling code - clean up authentication code - reload conf files on SIGHUP - rename SERVICE/SENDER_SERVICE to DESTINATION/SENDER - fix circular conf file inclusion - allow empty arrays - tons of other small bugfixes D-BUS 0.21 === - implement "auto activation" flag on messages, so the destination service can be launched automatically - fix a bug in custom type marshaling - optimize case where multiple apps activate the same service (avoid "thundering herd") - add dynamic service file discovery/reloading - fix a busy loop when blocking for a reply - fix a 64-bit crash involving varargs - fix a bus crash when processing an AcquireService - allow appending TYPE_BYTE via append_args_valist - fix dicts-inside-dicts - enhancements to Python and Qt bindings D-BUS 0.20 === This release lands some very large API changes and numerous bugfixes. The list of changes is too large to fully document here; please refer to the documentation, and message-bus-list archives. D-BUS 0.13 === This is probably the last release before landing the large API changes on the "dbus-object-names" branch. - fix system bus to always use filesystem socket; anyone can create any abstract socket, which isn't secure since if you can crash the system bus you'd be able to replace it. - add DTD for configuration file - improve specification a bit D-BUS 0.12 === - fix "service messagebus status" on Red Hat - fix demarshaling of DBUS_TYPE_NAMED - fix "eval `dbus-launch --exit-with-session`" to exit properly - fix build without --prefix - useless fooling with Mono bindings - useless fooling with gcj bindings - fix srcdir != builddir - fix various compiler warnings and other issues - add get/set data to DBusMessage - fix headers for C++ - OS X build fixes - abstract domain sockets support (Linux only) - add dbus-cleanup-sockets utility for people not using linux - be consistent about defaulting to --session/--system with command line tools - merge in policies from included config files - fix build on non-x86 - docs updates - lots of other bugfixes D-BUS 0.11 === - add --enable-docs to turn off/on the docbook stuff (doesn't cover doxygen stuff yet) - make people define DBUS_API_SUBJECT_TO_CHANGE and read warning in README so they don't expect the API to be frozen already - rename .pc files to "dbus-1.pc" instead of "dbus-1.0.pc" etc. - this will require changing pkg-config invocations - some docs cleanups - add man pages for all executables - allow send to/from bus driver in the default system.conf - fix user lookup bug - implement dbus-launch to launch the session message bus - fix some thread deadlocks - some performance profiling/optimization - add dbus_bus_activate_service() function - fix some minor bugs here and there - install Red Hat initscript in the right place D-BUS 0.10 === - reversed order of args to dbus_message_new() - renamed dbus_message_name_is() and some other functions - change DBusWatch to have dbus_watch_handle() similar to dbus_timeout_handle(), drop connection/server-specific handle routines - change message serials to be unsigned - implemented // features for config file; system bus now has a deny-all policy by default. - system.conf has system.d so packages can install additions to the default policy to the messages they need. e.g. CUPS might install a cups.conf - see test/data/valid-config-files/system.d/test.conf for an example. - add timeouts for authentication, activation - add glib-style "checks" on public API, enable those by default, disable assertions by default - add GMainContext argument to GLib setup functions, can be NULL for default context. Needed for threads. - add 64-bit integer type - validate type of standard message header fields - consider messages in the org.freedesktop.Local namespace to be invalid (to avoid fake disconnect messages for example) - fix assorted memory leaks and other bugs in the SHA-1 auth mechanism - cache user database information (groups user is in, etc.) helps a lot with NIS - always store uid_t, pid_t, gid_t in "ulong" rather than "int" - implement config file settings for which users can connect - SHA-1 unit test - dbus-send, dbus-monitor command line utilities - fixed lots of misc crashes and other bugs D-BUS 0.9 === - implemented a test case for service activation, and fixed many bugs exposed by that - implemented recursive argument marshaling/demarshaling for messages, allowing multidimensional arrays - fixed up integration of message dispatch with main loop by adding a callback on change of dispatch status - add a pidfile feature to daemon - some build fixes - clean up unix domain sockets on exit - add --print-address and the ability to create a random server address in a temporary directory D-BUS 0.8 === - fix dumb bug in 0.7 D-BUS 0.7 === - implement configuration file used to control bus characteristics - implement daemon mode, changing user ID, and other system bus features - add init scripts for systemwide bus - add "make check-coverage" target to check test coverage - more test suite additions - many, many bugfixes - many API changes/fixes D-BUS 0.6 === - Vastly improved bus daemon test suite - Lots of misc. bugfixes and memory leak fixes - Support for marshalling key/value data - Activation improvements. D-BUS 0.5 === - Specification updates - port to OS X and other BSD variants - port to Solaris - Partial work on cookie-based authentication - Thread safety fixes - Lots of misc. bugfixes - Support for more array types - Add data slots to DBusServer - DBusString security audit fixes - Fix for systems (or valgrind) with unaligned malloc blocks D-BUS 0.4 === - Preliminary activation support. - Better authentication test suite - Bus test program - Specification updates - Thread safety - Bug fixes D-BUS 0.3 === - Preliminary limitations - Message sending works - Bus client - Array marshalling/demarshalling - Services - Better OOM handling in the bus - In-proc debug transport - Transport/server address support D-BUS 0.2 === - Include test code in the tarball. D-BUS 0.1 === - Initial release. dbus-1.10.6/ChangeLog.pre-1-00000644000175000017500000177301312602773110015403 0ustar00smcvsmcv000000000000002006-11-09 John (J5) Palmieri * Released 1.0.0 2006-11-09 John (J5) Palmieri * AUTHORS: added Peter and Tor of windows porting fame 2006-11-08 Havoc Pennington * doc/dbus-specification.xml: add a note about protocol stability * doc/TODO: Remove "important for 1.0" section, replace with "important for 1.2" section 2006-11-08 John (J5) Palmieri * README: remove some of the out of date flags * doc/TODO: Remove todo items which are done 2006-11-08 John (J5) Palmieri * tools/dbus-monitor.c: Handle sigint so we flush stdout (Patch from Olli Salli ) 2006-11-08 John (J5) Palmieri * tools/dbus-monitor.1: update the manpage for dbus-monitor (Patch from Olli Salli ) 2006-11-08 John (J5) Palmieri * AUTHORS: Update with all people listed in the ChangeLog 2006-11-08 John (J5) Palmieri * tools/dbus-monitor.c: add profiling tools to dbus-monitor (Patch from Olli Salli ) 2006-11-07 Havoc Pennington * HACKING: Update release instructions to include stuff about stable releases, branching, etc. May not be totally correct, please fix if needed, but keep instructions up-to-date so we do each stable release consistently in the future. 2006-11-07 Havoc Pennington * doc/dbus-specification.xml, doc/dbus-faq.xml, README: various documentation updates. Bump faq/spec versions (not to 1.0; I don't think the spec will be "finished"/1.0 when we ship the 1.0 library). 2006-11-06 John (J5) Palmieri * bus/bus.c: Missed patch - pass in the context to the directory watch 2006-11-02 John (J5) Palmieri * Released D-Bus 1.0 RC 3(0.95) 2006-11-02 John (J5) Palmieri * bus/activation.c (bus_activation_new): don't fail if we can not read the directory as it may not exist 2006-11-02 John (J5) Palmieri * bus/config-parser.c (service_dirs_find_dir): use _dbus_list_get_next_link so we don't get stuck in an infinite loop (start_busconfig_child): move processing of standard_session_servicedirs tags here because they have no content (bus_config_parser_content): check we don't have content in standard_session_servicedirs tag 2006-11-02 John (J5) Palmieri * tools/Makefile.am: Make sure the /var/lib/dbus directory is created Packagers need to own this directory 2006-11-02 John (J5) Palmieri * tools/run-with-tmp-session-bus.sh: fixed script to replace the tag with a tag that points to the test service directory 2006-11-02 John (J5) Palmieri * configure.in: Add a check for DIR *dirp->dd_fd * dbus/dbus-sysdeps-util-unix: if HAVE_DDFD is defined use DIR *dirp->dd_fd else use DIR *dirp->__dd_fd. This takes care of both Solaris and Irix 2006-11-01 Havoc Pennington * bus/dbus-daemon.1.in: document standard_session_servicedirs 2006-11-01 John (J5) Palmieri * configure.in: expose DBUS_DATADIR * bus/config-parser.c: add the standard_session_servicedirs element to the parser (bus_config_parser_content): process the standard_session_servicedirs element by getting the standard directories from sysdeps and merging them into the service directory list (test_default_session_servicedirs): make sure we get what we expect * bus/session.conf.in: replace the servicedir tag with the standard_session_servicedirs tag * dbus/dbus-list.h: remove the typedef of DBusList and place it in dbus-sysdeps.h to avoid circular header dependencies * dbus/dbus-sysdeps.h: add the typedef of DBusList * dbus/dbus-sysdeps-unix.c (split_paths_and_append): utility function which takes a string of directories delimited by colons, parses them out, appends a suffix and puts them in a list ignoring empty elements (_dbus_get_standard_session_servicedirs): returns the standard directories for a session bus to look for service activation files on Unix which includes the XDG_DATA_HOME, XDG_DATA_DIRS and DBUS_DATADIR directories * test/data/valid-config-files/many-rules.conf: add the standard_session_servicedirs tag to the valid config file tests 2006-10-30 Havoc Pennington * tools/dbus-launch.1, doc/TODO: capture intent to change the command line options of dbus-launch a bit post 1.0 2006-10-27 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_open_private): document how to choose shared vs. private connections 2006-10-27 Havoc Pennington * dbus/dbus-test.c: enclose more of the file in the DBUS_BUILD_TESTS check. * dbus/dbus-sysdeps-pthread.c (PTHREAD_CHECK): fix for DBUS_DISABLE_ASSERT case. * dbus/dbus-connection.c (dbus_connection_get_unix_user): document that it only works on the server side * dbus/dbus-bus.c: add a global lock covering the BusData we attach to each connection (internal_bus_get): lock our access to the BusData (dbus_bus_register): lock the entire registration process with _DBUS_LOCK(bus_datas). If we get the lock and registration is already complete, silently return (vs. previous behavior of aborting). (dbus_bus_set_unique_name): lock the BusData (dbus_bus_get_unique_name): lock the BusData 2006-10-27 John (J5) Palmieri * bus/config-parser.c (service_dirs_find_dir, service_dirs_append_unique_or_free, service_dirs_append_link_unique_or_free): New static methods for only appending unique service directory names into the service directory list (merge_included, bus_config_parser_content): Only add unique service directory names into the list 2006-10-27 Havoc Pennington * dbus/dbus-sysdeps-pthread.c: make the "count" and "holder" variables volatile, suggested by Thiago. Document struct fields. (PTHREAD_CHECK): remove pthread error checking if assertions are disabled, should reduce the no-assertions case to the bare minimum code. 2006-10-26 Havoc Pennington * dbus/dbus-sysdeps-pthread.c (_dbus_pthread_mutex_lock): change to be recursive (_dbus_pthread_mutex_unlock): make it recursive (_dbus_pthread_condvar_wait): save/restore the recursion count (_dbus_pthread_condvar_wait_timeout): save/restore the recursion count 2006-10-26 Havoc Pennington * doc/dbus-specification.xml: clarify the UUID text slightly * dbus/dbus-sysdeps-pthread.c: check for and mostly abort on pthread errors. Add DBusMutexPThread and DBusCondVarPThread in preparation for being able to extend them for e.g. recursive mutexes. 2006-10-26 Havoc Pennington * dbus/dbus-threads.[hc]: Documentation improvements. Clarify how condition variables relate to recursive mutexes. * dbus/dbus-sysdeps-pthread.c, dbus/dbus-sysdeps-win-thread.c, dbus/dbus-threads.c: Split the platforms-specific thread implementations into their own files. * dbus/dbus-sysdeps-pthread.c (_dbus_pthread_condvar_wait_timeout): invert the return value, it was backward. Not that anything uses it. 2006-10-26 John (J5) Palmieri * dbus-sysdeps-unix.c (_dbus_set_local_creds): Clean up the LOCAL_CREDS vs CMSGCRED stuff a bit. Prefer CMSGCRED. This needs to be cleaned up more. * doc/TODO: Add a todo that *BSD hackers should look at cleaning up the CREDS issue. 2006-10-26 John (J5) Palmieri * configure.in, dbus-1.pc.in: Check to see if thread methods are in glibc or libpthread and add -lpthread to the link stage if it is the latter 2006-10-26 Thiago Macieira * dbus/dbus-connection.c (_dbus_connection_open_internal): Fix bug 8780: the connection lock is only required while recording the shared connection, so protect only that code section. Don't require connection_lookup_shared to return a locked connection. 2006-10-26 Thiago Macieira * tools/dbus-launch-x11.c (get_session_file, init_x_atoms): check if get_machine_uuid() returns NULL before proceeding any further: we can't init the X atoms or create a session file name if there is no machine ID. This solves a crash reported by some users if --exit-with-session was used without --autolaunch= 2006-10-26 John (J5) Palmieri * tools/dbus-launch.c (main): run the dbus-daemon in the builddir if tests are enabled and the DBUS_USE_TEST_BINARY env variable is set * tools/run-with-tmp-session-bus.sh: set DBUS_USE_TEST_BINARY before we run dbus-launch * configure.in: define TEST_BUS_BINARY to be the full path to dbus-daemon in the build root 2006-10-25 Sjoerd Simons * dbus/Makefile.am: * tools/Makefile.am: * toos/dbus-uuidgen.1: Move the machine-id file to /var/lib/dbus 2006-10-24 David Zeuthen * dbus/dbus-threads.c (init_uninitialized_locks): Fix typo so it's _dbus_assert (thread_init_generation != _dbus_current_generation) not _dbus_assert (thread_init_generation == _dbus_current_generation) 2006-10-24 Thiago Macieira * dbus/dbus-sysdeps.h: * dbus/dbus-sysdeps-unix.c: Add function _dbus_make_file_world_readable that chmods a file to 0644. * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): Avoid writing to the static "argv" array, thereby avoiding a COW on the child process. * dbus/dbus-internals.c (_dbus_create_uuid_file_exclusively): call _dbus_make_file_world_readable on the created file. 2006-10-23 David Zeuthen * dbus/dbus-memory.c: Use atomic variable to protect n_blocks_outstanding otherwise OOM will be reported using SMP on some arches * bus/dispatch.c: Add missing end of line characters * bus/desktop-file.c (parse_section_start, parse_key_value) (bus_desktop_file_load): Propertly handle OOM * dbus/dbus-threads.c (init_uninitialized_locks): Check that thread_init_generation equals _dbus_current_generation, not 0 2006-10-22 Havoc Pennington * dbus/dbus-connection-internal.h: move prototype of _dbus_bus_notify_shared_connection_disconnected_unlocked() here so it isn't in a public header and doesn't end up in the DBusBus group in Doxygen 2006-10-21 Havoc Pennington * Makefile.am (EXTRA_DIST): dist cleanup-man-pages.sh so it's in the tarball if packagers want to run it * cleanup-man-pages.sh: Add a script which munges all the internal API man pages out of the Doxygen output. This reduces the size of the installed man pages from 7 to 2 megs, and avoids namespace-polluting pages. Right now (like Doxygen) this script isn't in the build, it's something packagers can do manually. 2006-10-21 Havoc Pennington * dbus/dbus-connection.h: don't include the watch/timeout functions in connection section 2006-10-21 Havoc Pennington * Documentation! Whee! Doxygen now 100% silent. If you make it angry again, you will be punished. 2006-10-21 Havoc Pennington * More documentation - all public API now documented according to Doxygen 2006-10-21 Havoc Pennington * Document a bunch of undocumented stuff 2006-10-21 Havoc Pennington * Clean up Doxygen group markers for public API so Doxygen finds everything (not comprehensively fixed for private API). Means all remaining Doxygen warnings are just about missing docs and thus pretty simple to resolve. 2006-10-21 Havoc Pennington * dbus/dbus-macros.h: add DBUS_GNUC_DEPRECATED macro * dbus/dbus-message.h: mark dbus_message_iter_get_array_len() as DBUS_GNUC_DEPRECATED 2006-10-21 Havoc Pennington * Move all private API into the private Doxygen group sections of the files, so they don't show up in the public API docs 2006-10-21 Havoc Pennington * dbus/dbus-message.h: put #ifndef DBUS_DISABLE_DEPRECATED around dbus_message_iter_get_array_len(). * throughout: documentation improvements. 2006-10-20 Havoc Pennington * doc/TODO: remove the int64 thing from 1.0 since it doesn't matter, and the message-loader-breaker thing since nobody is going to do it. Add an item to 1.0 about supporting recursive locks in dbus_threads_init_default() though, since it should be easy. * dbus/dbus-connection.c (_dbus_connection_read_write_dispatch): Fix this in the !dispatch case to avoid busy-looping after disconnection * More misc docs improvements 2006-10-19 Havoc Pennington * more Doxygen-related fixes (lots of moving things from the public to internal section in dbus-connection.c) 2006-10-19 Havoc Pennington * Fix a pile of Doxygen warnings and missing docs 2006-10-19 John (J5) Palmieri * bus/dir-watch-default.c, bus/dir-watch-dnotify.c, bus/dir-watch-kqueue.c (bus_watch_directory): Pass in a BusContext instead of a void *. kqueue uses this to get the context's loop while the other modules ignore the parameter. This allows us to avoid platform conditionals * bus/bus.c (process_config_postinit): Pass in the context to the watch 2006-10-19 John (J5) Palmieri * bus/messagebus.in, bus/rc.messagebus.in: run dbus-uuidgen --ensure when starting the system bus 2006-10-18 John (J5) Palmieri * configure.in: More fixups for cross compile (Patch from Marco Pracucci ) 2006-10-17 Havoc Pennington * tools/dbus-send.c (main): don't close shared connection, fix from Timo Hoenig 2006-10-17 Havoc Pennington * configure.in (CPPFLAGS): don't do -DDBUS_API_SUBJECT_TO_CHANGE here * dbus/dbus.h: drop the DBUS_API_SUBJECT_TO_CHANGE requirement, since realistically it doesn't look like we'll be changing it anymore. 2006-10-17 Havoc Pennington * dbus/dbus-internals.c (_dbus_warn_check_failed): new function to be used for return_if_fail type warnings; prefixes the pid, and fatal by default. 2006-10-14 John (J5) Palmieri * configure.in: Released 1.0 RC 2(0.94) Add check for -fPIC and enable it if available 2006-10-14 John (J5) Palmieri * doc/TODO: Remove the check TODO item 2006-10-13 John (J5) Palmieri * dbus-transport-socket.c (exchange_credentials): Print out more detailed errors if reading or sending credentials fail (Patch from Julio M. Merino Vidal ) 2006-10-13 John (J5) Palmieri * configure.in: when checking for posix getpwnam_r assume true for cross compiles 2006-10-13 John (J5) Palmieri * configure.in: Check for gethostbyname first before we check for it in libnsl. On gnu systems it is implemeneted 2006-10-13 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): fix to handle closed connections, from Tambet Ingo bug #8631 2006-10-11 John (J5) Palmieri * configure.in: use AC_TRY_COMPILE for dirfd instead of AC_TRY_RUN 2006-10-11 John (J5) Palmieri * test/name-test/Makefile.am: don't link against both libdbus and libdbus-convenience 2006-10-11 John (J5) Palmieri * configure.in: check for dirfd even if it is a macro (Patch from Timothy Redaelli ) 2006-10-08 John (J5) Palmieri * configure.in: define _POSIX_PTHREAD_SEMANTICS on solaris avoid using dirfd on systems that don't have dirfd (Patch by Brian Cameron ) 2006-10-02 John (J5) Palmieir * dbus/dbus-sysdeps.c (_dbus_abort): Remove from #ifndef DBUS_DISABLE_ASSERTS macro to fix distcheck * dbus/dbus-sysdeps-unix.c (_dbus_print_backtrace): Remove from #if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_BUILD_TESTS) macro because _dbus_abort calls it * tools/Makefile.am: Add dbus-launch.h to the source list so distcheck works 2006-10-02 John (J5) Palmieir * dbus/dbus-sysdeps-util-unix.c (dirent_buf_size): Add check for MAXNAMELEN for Mac OSX. (Patch from Jonas B ) 2006-10-02 Thiago Macieira * tools/dbus-launch.c (main): make it complain and abort execution in case an unknown option is given. Also, process the '--' argument as the end of arguments. 2006-10-01 Havoc Pennington * tools/dbus-launch.c (print_variables): if no syntax is given, don't print something that's sort-of-half-sh-syntax, just print a plain key-value pairs thing. * tools/dbus-launch-x11.c: use machine ID rather than hostname for the local machine representation (but still have the hostname in the display). Remove the hostname from the display if it is localhost. Change session files to be named ~/.dbus/session-bus/machine-display. Change X atoms to be underscore-prefixed so nobody whines about ICCCM compliance. Otherwise name them the same as the env variables. Change session file format to include key-value pairs and an explanatory comment. Keys are the same as the env variables. (set_address_in_x11): X property format can't depend on sizeof(pid_t) on a particular machine, fix to always be 32 bits * tools/dbus-launch.c: make --autolaunch take a machine id argument. If --autolaunch is used with a program to run, complain for now (but add a FIXME). Also, don't look for existing bus if there's a program to run (but add a FIXME). * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): pass machine uuid to dbus-launch (avoids linking dbus-launch to libdbus just to get this, and avoids duplicating uuid-reading code). * tools/dbus-launch.1: clarify various things 2006-10-01 Havoc Pennington * test/test-service.c (path_message_func): remove broken extra unref that was hidden by the bugs in dbus-connection.c/dbus-bus.c * test/test-shell-service.c (path_message_func): same fix * dbus/dbus-connection.c (_dbus_connection_get_dispatch_status_unlocked): break up the function a little for clarity and fix the notification of dbus-bus.c to not require dispatch to be complete * dbus/dbus-connection.c (dbus_connection_unref): improve the warning when you try to finalize an open connection. 2006-10-01 Havoc Pennington * dbus/dbus-bus.c (internal_bus_get): only weak ref the connection; this means _dbus_bus_notify_shared_connection_disconnected_unlocked can be called safely in any context (_dbus_bus_notify_shared_connection_disconnected_unlocked): don't unref * dbus/dbus-connection.c (_dbus_connection_get_dispatch_status_unlocked): move _dbus_bus_notify_shared_connection_disconnected_unlocked here when queuing Disconnected instead of when the Disconnected message arrives, so dbus_bus_get() won't return closed connections. 2006-10-01 Havoc Pennington * dbus/dbus-connection.c (_dbus_connection_close_if_only_one_ref): Add a hack to make DBusNewConnectionFunction work right. * dbus/dbus-server-socket.c (handle_new_client_fd_and_unlock): use the hack here. Also, fix the todo about refcount leak. * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): and use the hack here * dbus/dbus-connection.c: Kill the "shared" flag vs. the "shareable" flag; this was completely broken, since it meant dbus_connection_open() returned a connection of unknown shared-ness. Now, we always hold a ref on anything opened as shareable. Move the call to notify dbus-bus.c into connection_forget_shared_unlocked, so libdbus consistently forgets all its knowledge of a connection at once. This exposed numerous places where things were totally broken if we dropped a ref inside get_dispatch_status_unlocked where connection_forget_shared_unlocked was previously, so move connection_forget_shared_unlocked into _dbus_connection_update_dispatch_status_and_unlock. Also move the exit_on_disconnect here. (shared_connections_shutdown): this assumed weak refs to the shared connections; since we have strong refs now, the assertion was failing and stuff was left in the hash. Fix it to close still-open shared connections. * bus/dispatch.c: fixup to use dbus_connection_open_private on the debug pipe connections * dbus/dbus-connection.c (dbus_connection_dispatch): only notify dbus-bus.c if the closed connection is in fact shared (_dbus_connection_close_possibly_shared): rename from _dbus_connection_close_internal (dbus_connection_close, dbus_connection_open, dbus_connection_open_private): Improve docs to explain the deal with when you should close or unref or both * dbus/dbus-bus.c (_dbus_bus_notify_shared_connection_disconnected_unlocked): rename from _dbus_bus_check_connection_and_unref_unlocked and modify to loop over all connections * test/test-utils.c (test_connection_shutdown): don't try to close shared connections. * test/name-test/test-threads-init.c (main): fix warnings in here * dbus/dbus-sysdeps.c (_dbus_abort): support DBUS_BLOCK_ON_ABORT env variable to cause blocking waiting for gdb; drop DBUS_PRINT_BACKTRACE and just call _dbus_print_backtrace() unconditionally. * configure.in: add -export-dynamic to libtool flags if assertions enabled so _dbus_print_backtrace works. * dbus/dbus-sysdeps-unix.c (_dbus_print_backtrace): use fprintf instead of _dbus_verbose to print the backtrace, and diagnose lack of -rdynamic/-export-dynamic 2006-09-30 Havoc Pennington * dbus/dbus-bus.c (dbus_bus_get_private, dbus_bus_get) (internal_bus_get): fix screwy code formatting. whoever committed that was not paying attention! 2006-09-30 Havoc Pennington * configure.in (LT_CURRENT, LT_AGE): increment current and age to reflect addition of interfaces. * doc/dbus-specification.xml: describe a new org.freedesktop.DBus.Peer.GetMachineId method * dbus/dbus-string.c (_dbus_string_skip_white_reverse): new function (_dbus_string_skip_white, _dbus_string_skip_blank): use new DBUS_IS_ASCII_BLANK, DBUS_IS_ASCII_WHITE macros and fix assertion at end of skip_white (_dbus_string_chop_white): new function * bus/connection.c (bus_connections_setup_connection): call dbus_connection_set_route_peer_messages. * dbus/dbus-connection.c (_dbus_connection_peer_filter_unlocked_no_update): modify to support a GetMachineId method. Also, support a new flag to let the bus pass peer methods through to apps on the bus, which can be set with dbus_connection_set_route_peer_messages. Finally, handle and return an error for anything unknown on the Peer interface, which will allow us to extend the Peer interface in the future without fear that we're now intercepting something apps were wanting to see. * tools/dbus-uuidgen.c: a thin wrapper around the functions in dbus/dbus-uuidgen.c * dbus/dbus-uuidgen.c: implement the bulk of the dbus-uuidgen binary here, since most of the code is already in libdbus * dbus/dbus-sysdeps.c (_dbus_read_local_machine_uuid): read the uuid from the system config file * dbus/dbus-internals.c (_dbus_generate_uuid, _dbus_uuid_encode) (_dbus_read_uuid_file_without_creating) (_dbus_create_uuid_file_exclusively, _dbus_read_uuid_file): new uuid-related functions, partly factored out from dbus-server.c * dbus/dbus-sysdeps.c (_dbus_error_from_errno): convert EEXIST to DBUS_ERROR_FILE_EXISTS instead of EEXIST * dbus/dbus-protocol.h (DBUS_ERROR_FILE_EXISTS): add file exists error * tools/dbus-cleanup-sockets.1: explain what the point of this thing is a bit more * autogen.sh (run_configure): add --config-cache to default configure args * dbus/dbus-internals.h (_DBUS_ASSERT_ERROR_IS_SET): disable the error set/clear assertions when DBUS_DISABLE_CHECKS is defined * tools/dbus-launch.c (main): if xdisplay hasn't been opened, don't try to save address, fixes crash in make check 2006-09-30 Thiago Macieira * configure.in: add DBUS_BINDIR as a #define to C source code. * tools/dbus-launch.c * tools/dbus-launch.h * tools/dbus-launch-x11.c: * tools/dbus-launch.1: Add the --autolaunch option to dbus-launch, which makes it scan for an existing session started with --autolaunch. With that option, it also creates an X11 window and saves the bus address and PID to it. * dbus/dbus-sysdeps.h: * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): Add a function that runs "dbus-launch --autolaunch" to retrieve the running D-Bus session address (or start one if none was running) * dbus/dbus-transport.c: Add the handler for the "autolaunch:" address protocol, which tries to get the running session from dbus-launch. * dbus/dbus-bus.c: * dbus/dbus-internals.h: Make "autolaunch:" be the default D-Bus session bus address. * dbus/dbus-connection.c: Fix horrible typo in error message. 2006-09-18 John (J5) Palmieri * tools/Makefile.am: use @EXPANDED_DATADIR@ instead of @DATADIRNAME@ 2006-09-17 Havoc Pennington * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): fix so that if unix_user_function is set on windows, we still do the default check that the auth identity matches the bus identity 2006-09-16 Havoc Pennington * dbus/dbus-transport.c (_dbus_transport_open): modify to delegate to _dbus_transport_open_platform_specific, _dbus_transport_open_socket, and _dbus_transport_open_debug_pipe * dbus/dbus-transport-protected.h: add _dbus_transport_open_platform_specific 2006-09-16 Havoc Pennington Attempt auditing public API to remove all cases where a Unix function returns weird emulated goo to Windows. This probably breaks the bus daemon on Windows, to fix it again we may need to stop processing unix-specific config options on Windows, and may need to add Windows-specific public API or config options. * configure.in (LT_CURRENT, LT_AGE): increment current and age, to reflect added interfaces; should not break soname. * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): do not invoke unix user function on Windows. Kind of a hacky fix, but we don't want a "unix uid" leaking out on Windows. * dbus/dbus-connection.c (dbus_connection_get_socket): add new API to get the socket fd on Windows or UNIX (dbus_connection_get_unix_fd): make this always fail on Windows 2006-09-16 Havoc Pennington * dbus/dbus-server.c (dbus_server_listen): change how this works to be able to delegate to a set of handlers that can succeed, fail, or choose not to handle. Allows us to have dbus_server_listen_platform_specific. * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): factor out the tcp socket stuff to be used on windows, leaving unix domain socket only in dbus-socket-unix.c * dbus/dbus-transport-socket.c (_dbus_transport_new_for_tcp_socket): factor out the tcp socket stuff to be used on windows, leaving unix domain socket only in dbus-transport-unix.c * dbus/dbus-connection.c (dbus_connection_get_unix_user): insert temporary hack to be sure this fails on windows (dbus_connection_get_unix_process_id): ditto 2006-09-16 Havoc Pennington * dbus/dbus-sysdeps-unix.c (_dbus_open_tcp_socket) (_dbus_open_unix_socket, _dbus_open_socket): change API for _dbus_open_socket so the domain/type/protocol from system headers are not required. This is kind of pointless though unless we move part of _dbus_connect_tcp_socket into sysdeps.c instead of sysdeps-unix.c, which would mean adding a wrapper around bind/listen/etc. Also, add DBusError to the socket-opening functions so they don't require use of errno. 2006-09-16 Havoc Pennington * dbus/dbus-sysdeps-unix.h: small change to Peter's patch to make dbus-sysdeps-unix-util.c build, add unix-specific sysdeps header. * dbus/dbus-sysdeps.h, dbus-sysdeps-unix.c: patch from Peter Kümmel bug #8249 to make the sysdeps.h read/write/open/close functions specifically for sockets only, and move generic read/write/open/close into unix-specific code. 2006-09-14 Havoc Pennington * dbus/dbus-transport-unix.c (unix_do_iteration): fix a valgrind complaint about accessing revents when poll returns 0, from Julian Seward. 2006-09-14 John (J5) Palmieri * Released 1.0 RC 1 (0.93) 2006-09-14 John (J5) Palmieri * dbus/dbus-sysdeps-util-unix.c (_dbus_write_pid_file): use _dbus_close instead of close 2006-09-14 John (J5) Palmieri * dbus/dbus-sysdeps.c: Add support for LOCAL_CREDS socket credentials. Fixes "external" authentication under e.g. NetBSD which does not support any other socket credentials mechanism. (Patch from Julio M. Merino Vidal ) 2006-09-14 John (J5) Palmieri * dbus/dbus-threads.c: Allow recursive mutex's to be passed into dbus_threads_init and be used by the dbus mutex functions to avoid deadlocks. * doc/TODO: Remove recursive mutex dbus_connection_dispatch TODO item 2006-09-13 John (J5) Palmieri * dbus/dbus-sysdeps-util-unix.c (_dbus_directory_get_next_file): use threadsafe readdir_r instead of readdir 2006-09-13 John (J5) Palmieri * dbus-threads.c (dbus_threads_init_default): New method for initializing the internal thread implementation (Patch from Alexander Larsson ) 2006-09-11 John (J5) Palmieri * remove a bunch of todo items from the 1.0 list 2006-09-11 John (J5) Palmieri * bus/activation.c, bus/desktop-file.c: Distinguish between OOM and key not found 2006-09-11 John (J5) Palmieri * dbus/dbus-internal.c: Add dbus_is_verbose so we can have more complex debugging code * dbus/dbus-marshal-basic.c (_dbus_marshal_read_fixed_multi): Move between the test suite ifdefs (_dbus_verbose_bytes): return if verbosity is not enabled 2006-09-11 John (J5) Palmieri * dbus/dbus-marshal-recursive-util.c, dbus/dbus-marshal-recursive.c: remove DBusMark 2006-09-10 Havoc Pennington patch mostly by Peter Kümmel, bug #8211 * dbus/dbus-sysdeps-unix.c: new file, which splits out unix-specific stuff in dbus-sysdeps.c * dbus/dbus-sysdeps.c: don't include any UNIX-only headers, and move unix-specific stuff to dbus-sysdeps-unix.c * configure.in: check HAVE_ERRNO_H 2006-09-08 John (J5) Palmieri * bus/test-main.c (main): Initialize threading during tests * dbus/dbus-connection.c (_dbus_connection_new_for_transport): Unlock connection on error (generate_local_error_message): static method for generating an error message when we don't have a message to reply to (_dbus_connection_block_pending_call): Send a disconnect error instead of just a timeout (NULL) when the bus gets disconnected while blocking for a reply. 2006-09-08 John (J5) Palmieri * dbus/dbus-connection.c (dbus_connection_dispatch): Properly remove filters (Patch from Kimmo Hämäläinen ) 2006-09-07 John (J5) Palmieri * dbus/dbus-connection-internal.h: Add prototype for _dbus_connection_test_get_locks to remove warning 2006-09-07 John (J5) Palmieri * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): Make sure we close child_err_report_pipe[WRITE_END] on exec (Patch from Kimmo Hämäläinen ) 2006-09-07 John (J5) Palmieri * Clean up close calls to use _dbus_close (Patch from Kimmo Hämäläinen ) 2006-09-06 John (J5) Palmieri * doc/TODO: - Remove pending call locking todo item - dbus_connection_open now holds hard ref. Remove todo item - do proper locking on _dbus_bus_check_connection_and_unref and handle DBUS_BUS_STARTER. Remove todo item - Warn on closing of a shared connection. Remove todo item * bus/bus.c, bus/connection.c, bus/dispatch.c, dbus/dbus-bus.c, dbus/dbus-connection.c: Use the dbus_connection_close_internal so we don't get the warning when closing shared connections * test/test-service.c, test/test-shell-service.c: Applications don't close shared connections themselves so we unref instead of close * test/test-utils.c (test_connection_shutdown): Close the connection * dbus/dbus-bus.c (_dbus_bus_check_connection_and_unref): Changed to _dbus_bus_check_connection_and_unref_unlocked since we only call this method on a locked connection. Make sure we call _dbus_connection_unref_unlocked instead of dbus_connection_unref also. Handle DBUS_BUS_STARTER correctly * dbus/dbus-connection.c (connection_record_shared_unlocked): Mark as shared and hard ref the connection (connection_forget_shared_unlocked): Remove the hard ref from the connection (_dbus_connection_close_internal_and_unlock): New internal function which takes a locked connection and unlocks it after closing it (_dbus_connection_close_internal): New internal function which acts like the origonal dbus_connection_close method by grabbing a connection lock and calling _dbus_connection_close_internal_and_unlock (dbus_connection_close): Public close method, warns when the app trys to close a shared connection 2006-09-06 John (J5) Palmieri * bus/driver.c: (bus_driver_generate_introspect_string): New method for populating a DBusString with the introspect data (bus_driver_handle_introspect): Move introspect generation code to bus_driver_generate_introspect_string * bus/main.c: (introspect): New function which prints out the intropect data and exits (main): Add a --introspect switch 2006-09-06 John (J5) Palmieri * doc/TODO: Removed dtd publishing item. It seems the dtd has already been added at http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd 2006-09-05 John (J5) Palmieri * doc/TODO, various source files: Audited todo's and FIXME's and prepended the ones we should be looking at with 1.0. Those prepended with 1.0? need clerification or might not be needed for 1.0 2006-09-05 John (J5) Palmieri * dbus/dbus-pending-call.c: Add some checks so we don't crash on NULL in the public API (Patch from Kimmo Hämäläinen ) 2006-09-05 John (J5) Palmieri * configure.in: Fix for OS-X compile time endian issues (patch from Benjamin Reed ) 2006-09-05 John (J5) Palmieri * configure.in: Check for no-common compiler flag (OS-X fix from Benjamin Reed ) 2006-09-01 John (J5) Palmieri * tools/dbus-launch.c: Add a sigterm handler (patch from Frederic Crozat ) 2006-08-29 Havoc Pennington * test/test-service.c (path_message_func): fix lack of return value * dbus/dbus-sysdeps.c (_dbus_printf_string_upper_bound): fix formatting, remove #ifdef, and fix docs. #ifdef doesn't make any more sense than on anything else in this file. (_dbus_get_tmpdir): add const to return value, and keep the results of the various getenv around in a static variable. 2006-08-29 Havoc Pennington * dbus/dbus-sysdeps-util.c, dbus/dbus-sysdeps-util-unix.c: change from Ralf Habacker to move UNIX-specific sysdeps into a separate file. 2006-08-25 John (J5) Palmieri * test/Makefile.am: change find to use syntax that works with non gnu versions of find 2006-08-25 John (J5) Palmieri * dbus/dbus-transport.c: fix invalid deref when checking if a vtable method exists (Patch from Christian Ehrlicher ) 2006-08-25 John (J5) Palmieri * configure.in, dbus/Makefile.am, test/name-test/run-test.sh, test/name-test/Makefile.am: Fixed some issues with getting get dbus to build with builddir != srcdir (Taken from a patch by Bernard Leak ) 2006-08-25 John (J5) Palmieri * configure.in: Fix DBUS_DAEMONDIR to use EXPANDED_BINDIR for the default case 2006-08-25 John (J5) Palmieri * configure.ac, bus/Makefile.am: Generalize kqueue support so that it works on any system providing this interface, not only FreeBSD. For example, NetBSD. (Patch by Julio M. Merino Vidal ) 2006-08-20 Havoc Pennington * doc/dbus-faq.xml, doc/dbus-tutorial.xml: some improvements to the docs 2006-08-18 John (J5) Palmieri * Released 0.92 2006-08-18 John (J5) Palmieri * dbus/dbus-threads.c (dbus_threads_init): change the documentation to reflect the init late change * bus/bus.c (bus_context_new): Check user before we fork so we can print out an error message a user will be able to see 2006-08-18 John (J5) Palmieri Patch provided by Ralf Habacker (ralf dot habacker at freenet dot de) * dbus/dbus-sysdeps.c, dbus/dbus-threads.c, dbus/dbus-internals.h: Add two more global locks for use on windows platforms. These are unused on non-windows platforms but are not ifdefed out to avoid potential bugs (i.e. the few bytes lost does not warrent the extra maintanence and complexity that having seperate sets of locks would cause) 2006-08-18 John (J5) Palmieri * bus/services.c (bus_registry_acquire_service): Return an error when an application tries to register the org.freedesktop.DBus Bus Name * bus/services.c (bus_registry_release_service): Return an error when an application tries to release the org.freedesktop.DBus Bus Name 2006-08-17 Alp Toker * doc/dbus-specification.xml: Fix some minor typos. 2006-08-17 John (J5) Palmieri * configure.in: use $with_init_scripts instead of $operating_system to determine where to store the pid since the init scripts manipulate the pid file (patch from Marcelo Ricardo Leitner . 2006-08-16 John (J5) Palmieri * dbus/dbus-threads.c: Add static DBusList *uninitialized_mutex_list and static DBusList *uninitialized_condvar_list to support new late initialization threading model. In this model threads can be initialized even after the D-Bus API has been used but still needs to be initialized before the second thread has been started. Mutexes and condvar addresses are stored in the two static lists and are replaced with actuall locks when threads are initalized. (_dbus_mutex_new_at_location): New method for creating a mutex and placing the location into the static list (_dbus_mutex_free_at_location): New method for removing a mutex location from the static list and freeing the mutex (_dbus_condvar_new_at_location): New method for creating a conditional variable and placing the location into the static list (_dbus_condvar_free_at_location): New method for removing a conditional variable location from the static list and freeing the conditional variable (init_uninitialized_locks): Atomic method which goes through the static lists of mutex and condvar location and updates them with actuall locks (init_global_locks): changed to init_locks * dbus/dbus-connection.c: (_dbus_connection_test_get_locks): New method for tests to check connections (_dbus_connection_new_for_transport): Use the new at_location mutex and condvar API (dbus_connection_allocate_data_slot): Pass in the global lock address to _dbus_data_slot_allocator_alloc * dbus/dbus-dataslot.c: (_dbus_data_slot_allocator_alloc): Use the address of the mutex instead of the mutex itself * dbus/dbus-message.c: (dbus_message_allocate_data_slot): Pass in the global lock address to _dbus_data_slot_allocator_alloc * dbus/dbus-pending-call.c: (dbus_pending_call_allocate_data_slot): Pass in the global lock address to _dbus_data_slot_allocator_alloc * dbus/dbus-server.c: (_dbus_server_init_base): Use the new at_location mutex API (dbus_server_allocate_data_slot): Pass in the global lock address to _dbus_data_slot_allocator_alloc * test/name-test/test-threads-init.c: New test case for late thread initialization 2006-08-14 John (J5) Palmieri * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_alloc): Change _dbus_abort to _dbus_assert_not_reached because _dbus_abort causes compile problems when asserts are turned off Keeping _dbus_warn for printing out the message so even if asserts are turned off the user gets the messages that something is wrong 2006-08-14 John (J5) Palmieri Patches by Kjartan Maraas * bus/services.c (bus_service_list_queued_owners): Add a pointer cast to fix compiler warning * dbus/dbus-dataslot.c (_dbus_data_slot_list_get): return a NULL instead of FALSE since the return type is not expecting a boolean * dbus/dbus-marshal-basic.c (_dbus_marshal_test): Remove unused variable * dbus/dbus-marshal-recursive-util.c (node_new): return a NULL instead of FALSE since the return type is not expecting a boolean * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): Send a NULL into _dbus_transport_new_for_fd instead of a FALSE because we are expecting a pointer not a boolean * dbus/dbus-sysdeps-util.c (_dbus_get_tmpdir): add void as the parameter so some compilers don't complain * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket, _dbus_transport_new_for_tcp_socket): Send a NULL into _dbus_transport_new_for_fd instead of a FALSE because we are expecting a pointer not a boolean * test/shell-test.c (test_command_line): cast the second argument to _dbus_list_append to avoid compiler warnings * test/test-names.c (main): remove unused variable * test/test-service.c (check_hello_from_self_reply): Initialize echo_message and echo_reply to NULL * test/test-shell-service.c (handle_echo): Remove unused variable and cast the third parameter passed to dbus_connection_get_object_path_data to avoid compiler warrnings * test/name-test/test-names.c (clear_message_queue): Remove unused function * test/name-test/test-pending-call-dispatch.c: Fix format string in printf 2006-08-14 John (J5) Palmieri * dbus/dbus-bus.c: * test/name-test/test-names.c: Remove test method dbus_bus_connection_get_unique_name because we already have public method dbus_bus_get_unique_name that does the exact same thing 2006-08-10 John (J5) Palmieri * dbus/dbus-signature.c: fix typos in Julio's previous patch which cause make check to fail 2006-08-10 John (J5) Palmieri * dbus/dbus-address.c (_dbus_address_test): Revert leaking strcmp. In any case it was wrong since this is a test checking to see if address parsing is correct. There was no need to get the true tmp directory. 2006-08-10 John (J5) Palmieri * dbus/dbus-macros.h: Revert the addition of stddef.h as we should not be adding it to library headers 2006-08-10 John (J5) Palmieri * dbus/dbus-signature.c: Fix the unit tests so that they work if assertions are not enabled. (patch from Julio M. Merino Vidal ) 2006-08-10 John (J5) Palmieri * tools/run-with-tmp-session-bus.sh: * test/name-test/run-test.sh: Remove bashisms (patch from Julio M. Merino Vidal ) 2006-08-10 John (J5) Palmieri * configure.in: add a version (>= 2.6.0) check for libxml2 2006-08-10 John (J5) Palmieri * configure.in: make sure the compiler supports -Wfloat-equal * bus/dir-watch-dnotify.c: move functional code after variable declerations (C99 fix) (patches from Jens Granseuer 2006-08-10 John (J5) Palmieri * dbus/dbus-macros.h: add #include so that Sun compilers don't complain about the defining NULL 2006-08-10 John (J5) Palmieri * dbus/dbus-sysdeps.c: * dbus/dbus-address.c: * bus/activation.c: * test/shell-test.c: don't hardcode tmp directory (patch from Dave Meikle ) 2006-08-09 John (J5) Palmieri * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_alloc): Change an assert to a detailed warning and abort. When allocator->lock != mutex it indicates that the user has failed to initalize threads before using the D-Bus library. This warning helps the user identify the issue and fix their app. 2006-08-08 John (J5) Palmieri These are all patches from Kjartan Maraas with cleanups of bugs found from Coverity reports: * dbus/dbus-sysdeps-util.c (_dbus_write_pid_file): close the file on error to avoid a leak * bus/expirelist.c (bus_expire_list_test): Check for NULL on dbus_new0 * bus/activation.c (update_directory): remove dead code * bus/config-parser.c (merge_service_context_hash, start_selinux_child): Fix some leaks * bus/bus.c (process_config_every_time): Fixed a leak * bus/desktop-file.c (parse_key_value): Fixed leak * bus/selinux.c (bus_selinux_id_table_insert): Fixed leak 2006-08-08 John (J5) Palmieri * dbus/dbus-object-tree.c (_dbus_object_subtree_new): remove dead code 2006-08-08 John (J5) Palmieri * tools/run-with-tmp-session-bus.sh: use #!/bin/sh instead of #!/bin/bash 2006-08-08 John (J5) Palmieri * Doxyfile.in: fix the INPUT line so we can generate docs when sourcedir != builddir (patch from Cygwin Ports maintainer 2006-08-08 John (J5) Palmieri * dbus/dbus-sysdeps.h: * dbus/dbus-sysdeps.c: * dbus/dbus-string.c: s/_dbus_printf_length/_dbus_printf_string_upper_bound to comform with GLib's function which does the same thing * configure.in: * bus/Makefile.am: * bus/dir-watch-default.c: * bus/dir-watch-dnotify.c: * bus/dir-watch-kqueue.c: Add kqueue directory watching for freebsd and split the directory watching code into seperate files per method/arch (patches from Timothy Redaelli ) 2006-08-08 John (J5) Palmieri * configure.in: * tools/Makefile.am: * tools/dbus-launch.c: * bus/Makefile.am: allow --with-dbus-daemondir switch to be used to make the daemon install to a seperate bindir like /usr/libexec (patch from Brian Cameron * bus/Makefile.am (install-data-hook): removed the slash after $(DESTDIR) so we don't get the double slash which does not work in windows (patch from Andras Porjesz ) 2006-08-08 John (J5) Palmieri * dbus/dbus-sysdeps.h: * dbus/dbus-sysdeps.c: add _dbus_printf_length (patch from Peter Kümmel ) 2006-08-08 John (J5) Palmieri * dbus/dbus-internals.c: unistd.h is not used (_dbus_verbose_real): only enable verbose printing if DBUS_VERBOSE environment var is set to '1' (patch from Peter Kümmel ) 2006-08-08 John (J5) Palmieri * configure.in: add a GCC flag check for -Wdeclaration-after-statement so we still compile on older gcc (patch from Frederic Peters 2006-08-04 Havoc Pennington * configure.in: add -Wdeclaration-after-statement * dbus/dbus-connection.c: change all the pending call stuff to reflect the fact that pending call operations use the connection lock * dbus/dbus-pending-call.c: add locking here * dbus/dbus-errors.c (struct DBusRealError): don't make the name field const consistent with how message field is done 2006-08-03 John (J5) Palmieri * s/D-BUS/D-Bus/g 2006-08-03 John (J5) Palmieri * dbus/dbus-object-tree.c: Patch by Benjamin Otte - fix invalid read/write reported by valgrind 2006-07-24 John (J5) Palmieri * Released 0.91 2006-07-22 John (J5) Palmieri * dbus/dbus-connection.c: (_dbus_connection_attach_pending_call_unlocked): (connection_timeout_and_complete_all_pending_calls_unlocked): Make sure we set timeout_added on pending calls to FALSE when we remove the timeout from the connection 2006-07-21 John (J5) Palmieri * Removed some extra bindings stuff lingering around (thanks timo) * dbus-pendingcall.c (_dbus_pending_call_new): s/dbus_connection_ref/_dbus_connection_ref_unlocked fixes assertion when we tried to take a lock on an already locked connection 2006-07-17 John (J5) Palmieri * Released 0.90 2006-07-17 Havoc Pennington * dbus/dbus-marshal-basic.c (_dbus_type_to_string): support 64-bit ints, reported by Owen Taylor 2006-07-17 John (J5) Palmieri * doc/TODO: * dbus/dbus-bus.c: * dbus-errors.c: * dbus/dbus-marshal-validate.c: Removed TODO items which were fixed or are no longer relevent 2006-07-17 John (J5) Palmieri * dbus-qt4-1.pc.in, dbus-sharp.pc.in: Remove stray files from the stripped bindings 2006-07-16 Havoc Pennington * dbus/dbus-pending-call.c (_dbus_pending_call_set_timeout_error): Improve the error message on reply timeout 2006-07-14 John (J5) Palmieri * Remove all bindings 2006-07-13 John (J5) Palmieri * dbus-connection.c (dbus_connection_send_with_reply): return TRUE and set pending_reply out arg to NULL is connection is disconnected (connection_timeout_and_complete_all_pending_calls_unlocked): New static method for cleaning up pending calls on disconnect (_dbus_connection_get_dispatch_status_unlocked): If we have pending calls queued timeouts on disconnect * dbus/dbus-pending-call.c (_dbus_pending_call_set_connection): Remove 2006-07-13 Carlos Garcia Campos * bus/activation.[ch] (bus_activation_list_services): new function to get the list of services that can be activated * bus/dispatch.c: test coverage for the new bus method ListActivatableNames * bus/driver.c: new bus method ListActivatableNames to get the list of services that can be activated * doc/dbus-specification.xml: ListActivatableNames method documentation 2006-07-12 John (J5) Palmieri * dbus/Makefile.am: add dbus-pending-call-internal.h to the list of source files 2006-07-12 John (J5) Palmieri * dbus/dbus-message-factory.c: Fix index into an array (patch by Peter Kümmel ) 2006-07-12 John (J5) Palmieri * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: * file dbus/dbus-pending-call.c: * dbus/dbus-pending-call.h: Make DBusPendingCall an opaque type even to D-Bus internals 2006-07-07 John (J5) Palmieri * dbus/dbus-connection.h: remove connection_disconnect and replace with connection_close * dbus/dbus-connection.c: include dbus-bus.h (_dbus_connection_read_write_dispatch): make static 2006-07-07 John (J5) Palmieri * dbus/dbus-connection.c (dbus_connection_close): removed deprecated function (dbus_connection_dispatch): On disconnect unref any shared connections * dbus/dbus-bus.c (_dbus_bus_check_connection_and_unref): new function for cleaning up shared connections on disconnect (internal_bus_get): get a hard refrence to shared connections when they are created * doc/TODO: Remove items which are no longer relevent or have been fixed Split 1.0 todo items with a 0.90 freeze todo list 2006-06-14 Ross Burton * glib/dbus-gobject.c: Free a leaking GArray (surely not!) in dbus_g_method_return. 2006-06-14 Ross Burton * tools/Makefile.am: * tools/dbus-monitor.c: Don't use the GLib bindings in dbus-monitor (patch from Ralf Habacker). 2006-06-14 Ross Burton * tools/dbus-print-message.c: Also print the object path when outputting signals or method calls. 2006-06-13 Thiago Macieira * qt/src/Makefile.am: install the qdbus.h header. This allows people to actually use the installed code. 2006-06-12 Ross Burton * glib/dbus-gproxy.c: Don't leak a GArray when firing signals (thank Rob Taylor for review). 2006-06-12 Thiago Macieira * Released 0.62 2006-06-12 Thiago Macieira * dbus/dbus-arch-deps.h.in: Remove spurious semi-colons that break pedantic builds. Closes bug 6043 (patch approved by Havoc back in February). 2006-06-12 Thiago Macieira * qt/src/qdbusintegrator.cpp: Fix bug in parsing async methods that took a QDBusMessage parameter. * qt/src/qdbusbus.h: Add a default flag for RequestName. * qt/tools/dbus.cpp: Don't use automatic call because we might be calling an async method: request a reply. 2006-06-11 Thiago Macieira * test/qt/*: Update the testcases, including testing the new functionality of sending null QByteArray and QString over the bus. Add new headertest test and restore the old qdbusxmlparser test. 2006-06-11 Thiago Macieira * qt/tools/dbuscpp2xml.cpp: Compile on Windows. * qt/tools/dbusidl2cpp.cpp: Add missing newline. * qt/examples/Makefile.am: * qt/examples/chat.h: Use UI-generated files with the ui_*.h form. * qt/src/qdbusmarshall.cpp: Allow sending of QString() and QByteArray() (nulls) over the bus. * qt/src/qdbusabstractinterface.cpp: Use the correct variable, the one that has the signature suffix stripped. * qt/src/qdbusreply.h: Make some methods const. 2006-06-09 Thiago Macieira Patch from Timo Hoenig . * qt/dbus/Makefile.am: New file. Fix "make dist", add all headers required during build to EXTRA_DIST. * qt/src/Makefile.am: Fix "make dist", add 'qdbus.h' to EXTRA_DIST. * qt/Makefile.am: Fix "make dist", add 'dbus' to DIST_SUBDIRS. * configure.in: Fix "make dist", take care that the Makefile for qt/dbus is being generated. 2006-06-07 John (J5) Palmieri * bus/bus.c: Fix eavesdropping on method calls 2006-06-07 John (J5) Palmieri * configure.in: * dbus/dbus-userdb-util.c: Add Solaris console owner patch from Artem Kachitchkine 2006-06-07 Thiago Macieira * qt/Makfile.am: * qt/src/Makefile.am: Fix the EXTRA_DIST after the reorganisation. Thanks to Timo Hoenig for pointing this out. 2006-06-06 Robert McQueen * glib/dbus-gtype-specialized.c: Fix obvious leak of GArray in every call to dbus_g_type_get_struct. 2006-06-06 Robert McQueen * glib/dbus-gvalue-utils.c: Fix the failing test where static string pointers were put into a GPtrArray-based specialised collection, and then freed along with the array. GValues which you add into collections or maps which have the NOCOPY flag set are assumed to not belong to the caller, so rather than the existing pointer-stealing semantics, they are copied instead. Given that the main consumers of this abstraction are the bindings themselves, I don't think this is too bad, but others should watch their choice of take vs set_static. 2006-06-06 Robert McQueen * glib/dbus-gvalue-utils.c: Spotted a warning about the return value of g_slist_prepend not being used. Fixed copying of slist-based specialised collections, then wrote a test case and found that it was all broken. Went on to fix iterating and appending too. Good thing nobody uses this code yet. 2006-06-06 Robert McQueen * glib/dbus-gvalue-utils.c: Remove duplicated code by having all of the iterators use gvalue_take_ptrarray_value (the GValues themselves are discarded without unsetting, so it makes no difference whether we take or set_static). Remove cases for G_TYPE_POINTER because there really is nothing useful we can do with them in our specialised types - we *need* boxed copy/free functions at the very least. 2006-06-05 Thiago Macieira * qt/dbus: Add directory. I had forgotten to add this yesterday after the move... * qt/examples/Makefile.am: * qt/examples/dbus.cpp: Moved to qt/tools/dbus.cpp. * qt/tools/Makefile.am: * qt/tools/dbus.cpp: Moved from qt/examples/dbus.cpp. Added feature to get and set properties. Added validation of service, object path and interface names. * qt/tools/dbusidl2cpp.cpp: Two new features: 1) Allow specifying both the header and the source file names, by separating them with a colon. 2) Don't write an interface output if the -p switch wasn't given, but the -a was. * qt/src/*: Fix usage of Iterators and ConstIterators. Fix shadowing of variables by other variables (-Wshadow). Fix keyword-cleanliness in headers. Fix ASCII-cast (QLatin1String, QLatin1Char). Fix validation of member names. Add extra checking of introspection data during XML parsing. Various bug fixes. 2006-06-04 Thiago Macieira * dbus/Makefile.am: * dbus/qdbus.h: Remove unnecessary file. This is mirrored into qt/dbus/qdbus.h now. 2006-06-04 Thiago Macieira * configure.in: Make --disable-qt actually do something. Patch inspired by Zack Rusin. 2006-06-04 Thiago Macieira * qt/: Update to Subversion r548032. This includes a big reorganisation of the files inside the subdir. 2006-05-30 Sjoerd Simons * dbus/dbus-sysdeps.c: Make tcp socket connection error somewhat more clear: "Failed to connect to socket : " instead of "Failed to connect to socket : :" * dbus/dbus-transport-unix.c: Fix crash when no host option is given for a tcp transport. 2006-05-29 Thiago Macieira * qt/*: Update the QtDBus bindings up to revision 546310 in Subversion. This adds the dbuscpp2xml tool, that parses a C++ header and outputs a D-BUS Introspection XML. 2006-05-21 Havoc Pennington * glib/dbus-gproxy.c: Put in a pile of assertions that the proxy name is not NULL when it shouldn't be. Also a couple of possible fixes for #4637 though I don't understand why the bug happens, to be honest... also the object constructor has an assert name != NULL and the name is only currently NULL for peer-to-peer proxies that I don't think anyone uses? So it should be asserting. Anyway, for now at least see if we get an earlier assertion failure. * glib/dbus-gvalue-utils.c: Put in a couple of assertions for apparently broken code to be sure the tests fail and someone will fix them... 2006-05-07 Thiago Macieira * qt/qdbusmarshall.cpp: Fix a problem of demarshalling lists and arrays when they had a single element: has_next returns false, even before you read the element. So, instead, check the array length. 2006-05-06 Thiago Macieira * qt/qdbusmessage.cpp: * qt/qdbustypehelper_p.h: * qt/qdbusintegrator.cpp: gcc 3.4 doesn't like Q_FOREACH when the list is a const-reference 2006-05-03 John (J5) Palmieri * Adding old doc patch that never got applied * dbus/bus.c (dbus_bus_add_match): Add documentation * doc/dbus-specification.xml: Add documentation for the match rules and the AddMatch and RemoveMatch methods 2006-05-02 Thiago Macieira * qt/dbusidl2cpp.cpp: There's no callAsync. Use the correct call (r535506) * qt/dbusidl2cpp.cpp: * qt/qdbusabstractadaptor.cpp: * qt/qdbusabstractadaptor.h: Make QDBusAdaptorConnector be a sibling of the QDBusAbstractAdaptor objects instead of the parent. (r535848) * qt/dbusidl2cpp.cpp: * qt/qdbusabstractinterface.cpp: * qt/qdbusabstractinterface.h: * qt/qdbusabstractinterface_p.h: * qt/qdbusinterface.cpp: Make properties in interfaces actually work. The code that was generated would not compile, due to moc calls to functions that did not exist. They now shall. (r536571) 2006-04-30 Thiago Macieira * Makefile.am: * configure.in: * dbus-qt4-1.pc.in: Add a pkg-config file for libdbus-qt4-1. Thanks to Brad Hards for providing the patch 2006-04-29 Thiago Macieira * qt/dbusidl2cpp.cpp: There's no callAsync. Use the correct call. (r535506) 2006-04-29 Thiago Macieira * qt/examples/dbus.cpp: Enhance error messages and use QDBusInterfacePtr. 2006-04-29 Thiago Macieira * qt/qdbusinterface.h: Rename QDBusRef to QDBusInterfacePtr and disable the copy operators. (r533772, r534746) * qt/qdbuserror.h: Remove the automatic cast to bool. (r533929) * qt/qdbusabstractinterface.cpp: * qt/qdbusabstractinterface.h: Change the default call mode to not use the event loop. Add convenience call() methods that take a CallMode parameter. (r534042) * qt/qdbusconnection.h: Change the default call mode to not use the event loop. (r534042) * qt/qdbusinterface.cpp: * qt/qdbusinterface.h: Add a method to tell us if the interface is valid (since we don't return a null pointer anymore) (r534099) * qt/qdbusinterface_p.h: Don't crash if metaObject is 0 (r534101) * qt/qdbusinternalfilters.cpp: Decouple the introspection function in two so taht we get the chance to introspect without having a QDBusMessage (r534102) * qt/qdbusbus.h: * qt/qdbusconnection.cpp: * qt/qdbusconnection_p.h: * qt/qdbusintegrator.cpp: Keep a list of our own names to avoid a round-trip to the server when attempting to introspect one of our own objects. Also make sure the filter functions match the empty interface as well. (r534108) Don't keep the connection names. Instead, trust the unique connection name (r534111) Remove event loop usage (r534112) 2006-04-29 Thiago Macieira * qt/qdbusintegrator.cpp: Fix assertion failure spotted by Brad Hards. 2006-04-28 Robert McQueen * glib/dbus-gproxy.c: Fix properties so that they can be given in any order, making it easier for people who inherit from this object. 2006-04-28 Robert McQueen * glib/dbus-gvalue-utils.c: Patch from Jakub Stachowski to fix leaking of memory from within pointer arrays and lists. Fixes bug #6300. 2006-04-28 Robert McQueen * glib/dbus-gvalue.c: Patch from Jakub Stachowski to fix a leak in generating struct signatures. Fixes bug #6083. 2006-04-28 Robert McQueen * qt/Makefile.am: Tweak CLEANFILES from qdbusconnection.moc to qdbusconnection_p.moc. 2006-04-24 John (J5) Palmieri * README, INSTALL: Doc fixes Patch from Brad Hards 2006-04-23 Thiago Macieira * qt/examples/dbus.cpp: Use the new merged-interface mode for the dynamic meta object. No need to guess which interface to call. 2006-04-23 Thiago Macieira * qt/qdbusconnection_p.h: * qt/qdbusmetaobject.cpp: * qt/qdbusmetaobject_p.h: * qt/qdbusintegrator.cpp: Use the new merged-interface mode for the dynamic meta object. No need to guess which interface to call. * qt/qdbusabstractinterface_p.h: * qt/qdbusconnection.cpp: * qt/qdbusintegrator.cpp: * qt/qdbusinterface.cpp: * qt/qdbusinterface.h: Make findInterface always return a non-null pointer. Add a QDBusRef that looks and behaves like DCOPRef. 2006-04-23 Thiago Macieira * dbus/dbus-connection.c: Interfaces are optional in method calls, so don't give up if the interface parameter is NULL. Patch reviewed by Havoc Pennington. 2006-04-23 Thiago Macieira * qt/qdbusreply.h: Add default constructor and operator= (r532625) * qt/qdbustypehelper_p.h: Use a clean namespace: no foreach() in public headers (r532952) * qt/qdbusabstractinterface.cpp: * qt/qdbusabstractinterface_p.h: Add the AutoDetect mode and make it the default (r532951) 2006-04-19 John (J5) Palmieri * dbus/dbus-connection.c: Fix asserts Patch from Tim Moloney 2006-04-19 John (J5) Palmieri * mono/Connection.cs, mono/Message.cs: Check Target type Patch from Aaron Bockover (abockover at novell.com) 2006-04-13 Thiago Macieira * INSTALL: fine-tune the requirements for the Qt4 binding. 2006-04-16 Daniel P. Berrange * tools/dbus-print-message.c: Added support for printing of all remaining data types. Fixed logic for indentation of compound data types. 2006-04-15 Daniel P. Berrange * INSTALL: fill out content of file providing DBus specific build installations, followed by generic Auto* INSTALL file content 2006-04-13 Thiago Macieira * qt/qdbusintegrator.cpp: Work around g++ 3.3 bug. Patch by Stefan Eilers. (r529537) 2006-04-13 Thiago Macieira * qt/qdbusinternalfilters.cpp: Don't show the parent's contents (r528208) 2006-04-10 Thiago Macieira * qt/Makefile.am: fix the dependency for qdbusconnection_p.moc. It's included in qdbusintegrator.cpp, not in qdbusconnection.cpp. Thanks to Jakub Stachowski for spotting this. 2006-04-10 Thiago Macieira * qt/examples/listnames.cpp: * qt/examples/Makefile.am: Three ways to list the names on the bus. 2006-04-10 Thiago Macieira * test/qt/tst_hal.cpp: Remove the waiting, since it's not needed anymore. Requires Qt 4.1.3 to work properly. (r528148) 2006-04-10 Thiago Macieira Merge from Subversion: * qt/qt-dbus.qdocconf: Update Trolltech's webpage link to something that exists (r526315) * qt/qdbusinternalfilters.cpp: Correctly detect non-scriptable slots/signals (r526316) * qt/qdbusinternalfilters.cpp: Fix the setProperty call and also return an unknown-method error if the parameters don't match for org.freedesktop.DBus.Properties. (r526842) * qt/examples/dbus.cpp: Allow passing of QVariants (r526843) * qt/qdbusintegrator.cpp: Restore the proper order of delivery: don't make method returns be delivered on priority (r528150) 2006-03-28 Thiago Macieira * configure.in qt/Makefile.am: add qt/examples * qt/examples: Add QtDBus example programs: - hello: Hello, World - ping: Simple method-calling program - pong: Simple object-exporting program (not using adaptors) - complexping: Interactive method-calling program (also gets and sets properties). - complexpong: Sample program exporting methods, signals and properties, using adaptors. - dbus: Simple implementation of a generic method-calling program, similar to 'dbus-send', but with semantics similar to 'dcop'. - chat: Simplistic chat program, implemented using signals and the system bus. Looks like IRC. 2006-03-28 Thiago Macieira * configure.in: Detect QtGui (necessary for one of the example programs). Note: this increases the minimum required version of Qt to 4.1.3. 2006-03-28 Thiago Macieira * test/qt/*: Sync with KDE Subversion revision 523647. Update the testcases to the new API. Remove testcases for classes that are no longer public or have been removed. 2006-03-28 Thiago Macieira * qt/*: * dbus/qdbus.h: Sync with KDE Subversion revision 523647. Hopefully, this will be the last of the source-incompatible changes. Documentation has been improved; support for QList has been added; QDBusObject is gone; QDBus(Abstract)Interface is now a QObject with auto-generated meta-object; QDBusIntrospection is marked private, since QMetaObject can be used now; lots of bugfixes. 2006-03-16 John (J5) Palmieri Patch from Milosz Derezynski * configure.in: Output the service directory in the configure summary * dbus-1.pc.in: Add session_bus_services_dir 2006-03-10 Ross Burton * tools/dbus-print-message.c: Add support for object paths and signatures. 2006-03-06 Sjoerd Simons * bus/bus.c: (bus_context_reload_config): Flush the user database cache on config reload. * bus/dbus-daemon.1.in: Also note that SIGHUP flushes the user/group information caches * dbus/dbus-hash.c: (_dbus_hash_table_remove_all): * dbus/dbus-hash.h: Add function to remove all entries from a hash table * dbus/dbus-userdb.c: (_dbus_user_database_flush): * dbus/dbus-userdb.h: Add function to flush all user/group information caches. 2006-03-06 Thiago Macieira * qt/dbusidl2cpp.cpp: * qt/Makefile.am: add the dbusidl2cpp tool, the replacement for dcopidl2cpp, found in the KDE installations (or the more modern kalyptus): generate Qt4 C++ code for the input XML introspection. Currently no IDL parsing. 2006-03-06 Thiago Macieira * test/qt/*: Update the self-tests. 2006-03-06 Thiago Macieira * qt/*: * dbus/qdbus.h: Sync with KDE Subversion revision 516237. This represents the first feature-complete version of the Qt4 bindings since I took ove maintainership. 2006-03-06 Thiago Macieira * qt/Doxyfile: Adding a Doxyfile for the Qt4 bindings dir. This is C++, so we can't use the DBus ones. 2006-03-02 John (J5) Palmieri * python/dbus_bindings.pyx: Remove refrence to sys/cdefs.h (Patch from Artem Kachitchkine ) 2006-03-02 John (J5) Palmieri * dbus/dbus-connection.c: (_dbus_connection_block_pending_call): Check to see if our data has already been read off the connection by another blocking pending call before we block in poll. (check_for_reply_and_update_dispatch_unlocked): Code taken from _dbus_connection_block_pending_call - checks for an already read reply and updates the dispatch if there is one. * test/name-test/test-pending-call-dispatch.c: New test for making sure we don't get stuck polling a dbus connection which has no data on the socket when blocking out of order on two or more pending calls. 2006-02-28 Thiago Macieira * qt/Makefile.am: Patch by Sjoerd Simons. More .moc issues: make/automake don't detect that we're talking about the same .lo file if I specify the full path to the source files. 2006-02-26 Havoc Pennington * bus/dbus-daemon.1.in: improve the language in a couple spots I noticed * dbus/dbus-bus.c (internal_bus_get): in the error message if the session bus variable is unset, suggest "man dbus-launch" and "man dbus-daemon" to figure out how to fix the problem 2006-02-25 Havoc Pennington * glib/dbus-glib-tool.c (usage): fix up the usage message, someone should make this thing use the new glib options parser 2006-02-25 Thiago Macieira * qt/Makefile.am: Patch by Sjoerd Simons. Fix the path to the .lo files taking moc sources. 2006-02-25 Havoc Pennington * dbus/dbus.h, dbus/Makefile.am: add dbus-signature.h to dbus.h and install it as a public header 2006-02-24 John (J5) Palmieri * Released 0.61 2006-02-24 John (J5) Palmieri * proxies.py: Fix the callchain 2006-02-24 John (J5) Palmieri * patch from Sjoerd Simons : * dbus/dbus-sysdeps-util.c (_dbus_group_info_free): Moved to dbus/dbus-sysdeps.c * dbus/dbus-userdb.c (_dbus_group_info_free_allocated): Don't call _dbus_group_info_free_allocated which causes infinite loop, correctly call _dbus_group_info_free 2006-02-20 Thiago Macieira * qt/qdbusinterface_p.h: * qt/qdbusinterface.cpp: Use the standard org.freedesktop.DBus.Method.NoReply annotation for the "async" calls instead of creating one for us. * qt/qdbusconnection_p.h: * qt/qdbusintegrator.cpp: Remove debugging code. * qt/qdbusintegrator.cpp: * qt/qdbusmessage.cpp: * qt/qdbusmessage_p.h: * qt/qdbusmessage.h: Change the behaviour of automatic reply-sending: now a reply is always sent, unless the caller didn't request one or if the user slot has already sent one. 2006-02-16 Robert McQueen * configure.in: Patch from Debian packages by Sjoerd Simons to add --with-qt-moc and --with-qt3-moc arguments so it's possible to build both bindings in the same tree. * qt/Makefile.am: Fix truncated value so that make dist works. 2006-02-16 Robert McQueen * acinclude.m4, configure.in: Patch from Brad Hards to avoid warnings from autoconf 1.9 by improving quoting, re-ordering a few checks, and a few other aesthetic tidy-ups. 2006-02-16 Robert McQueen * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Patch from Rob Taylor to correct a bogus assertion that the next element to read from the iter is fixed in size. This is not the case when you are at the end of the iter, because the next element type is INVALID. * dbus/dbus-string.c (_dbus_string_init_const_len): Correct a a bogus assert which means that you may not initialise a 0-length string unless you provide a non-NULL pointer. This prevented you from marshalling messages containing zero-length arrays in some cases. * glib/dbus-gvalue.c (demarshal_collection_array): Another patch from Rob to correct bogus asserts when trying to demarshal an array and get_fixed_array got you 0 elements. Append nothing to the GArray in this case. * test/glib/test-dbus-glib.c: Add a test case for round-tripping an empty array via the glib bindings. Without all of the above patches, this new test fails. 2006-02-16 Robert McQueen * glib/dbus-gmain.c: Make the previous commit compile. * python/_dbus.py, python/matchrules.py: Patch from Ole Andre Ravnaas to allow you to specify sender_keyword="foo", path_keyword="bar" when adding a signal listener, so that you can bind to signals generically but still do something useful in your callback. * python/dbus_bindings.pyx: Demarshal the byte type as unsigned chars so that they're not cast to chars and made negative. Thanks to Jakub Stachowski for reporting this and testing the fix. 2006-02-15 John (J5) Palmieri * dbus/dbus-glib.h: * glib/dbus-gmain.h: (dbus_g_connection_open): new method for openning a connection to an arbitrary address in the glib bindings * ChangeLog: checkin last entry which doesn't seem to be commited 2006-02-13 John (J5) Palmieri * tools/dbus-launch.c: Fixed sh syntax output 2006-02-13 Robert McQueen * glib/dbus-binding-tool-glib.c, glib/dbus-gmain.c, glib/dbus-gsignature.c, glib/dbus-gtype-specialized.c, glib/dbus-gtype-specialized.h, glib/dbus-gvalue-utils.c, glib/dbus-gvalue-utils.h, glib/dbus-gvalue.c: Patch from Rob Taylor to add a big missing piece of the glib bindings jigsaw puzzle. This modifies the existing specialised types to have N type parameters (rather than the current 1 or 2 for arrays and dictionaries respectively). You can then use this to get a glib type to represent any arbitrary D-Bus struct type using dbus_g_type_get_struct. The only implementation of these types is with GValueArrays as before, but it's now possible to store these in arrays, emit them in signals, etc. 2006-02-10 John (J5) Palmieri * dbus/dbus-signature.c (dbus_signature_iter_recurse): Correctly deal with nested arrays (Bug #5823) Patch by Thiago Macieira 2006-02-10 John (J5) Palmieri * mono/doc/Makefile.am: Fix parallel make problem with mono-doc (Bug #4213) Patch from Doug Goldstein 2006-02-10 John (J5) Palmieri * bus/connection.c (bus_connections_expect_reply): Make pending reply limit not common to all connections (Bug #5416) Patch from Kimmo Hämäläinen 2006-02-10 John (J5) Palmieri * tools/dbus-launch.c: Fixed csh syntax output (Bug #5720) 2006-02-10 John (J5) Palmieri * gcj/Makefile.am: point to correct jar command (Bug #4529) patch from Doug Goldstein 2006-02-09 Joe Shaw * mono/Arguments.cs: Fix a magic number in the mono bindings that doesn't work on 64 bit arches. Patch from Peter Johanson. 2006-01-27 Robert McQueen * glib/dbus-binding-tool-glib.[ch]: Patch based on Ricardo Kekki's patch to use an annotation org.freedesktop.DBus.GLib.ClientCSymbol when generating the client-side methods, instead of overloading CSymbol which broke everything horribly. My apologies. 2006-01-27 Robert McQueen * glib/dbus-gtype-specialized.[ch], glib/dbus-gvalue-utils.c: Patch by me and Rob Taylor to add a simple_free function to D-Bus map and collection types, which allows those types which can be freed with a GDestroyNotify (such as GHashTables and GArrays, but not GPtrArrays) to be stored as the values in hashtables. * test/glib/test-dbus-glib.c, test/glib/test-service-glib.{c,xml}: Patch by Rob Taylor to add nested dicts to the glib tests to check the above code works, and appears not to leak when called repeatedly. 2006-01-27 Robert McQueen * glib/dbus-gvalue.c (demarshal_valuearray): Patch from Rob Taylor to free a D-Bus allocated string with dbus_free () instead of g_free (). 2006-01-27 Iain Holmes * glib/dbus-gproxy.c (dbus_g_proxy_dispose): Protect the dispose method from being called multiple times. 2006-01-19 Robert McQueen * glib/dbus-binding-tool-glib.c: Patch from Rob Taylor to add support for generating bindings to arrays that are represented as GPtrArrays rather than GArrays (ie size-variable things, such as strings, objects, structs, etc). 2006-01-05 Robert McQueen * dbus/dbus-glib.h, glib/dbus-gproxy.c: Patch from Ricardo Kekki to make it possible to inherit from DBusGProxy, by splitting the DBusGProxy struct into a public part and a private part, and moving the setting of the DBusGProxyManager into a connection property, allowing proper GObject construction. 2006-01-05 Robert McQueen * glib/dbus-binding-tool-glib.c: Patch from Ricardo Kekki to make dbus-binding-tool heed C symbol name annotations when generating glib client bindings. 2005-12-19 John (J5) Palmieri * dbus/dbus-shared.h: Call it shared constants instead of shared macros * dbus/dbus-protocol.h: add DOxygen markup to quiet warnings 2005-12-19 John (J5) Palmieri * dbus/dbus-shared.h: add DOxygen markup to quiet warnings 2005-12-19 John (J5) Palmieri * dbus/dbus-macros.h: correct DOxygen end of section (s/}@/@}) 2005-12-19 Ross Burton * doc/dbus-tutorial.xml: Document the Glib client-side bindings, and list all possible annotations. 2005-12-19 John (J5) Palmieri * dbus/bus.c (dbus_bus_release_name): Add documentation 2005-12-06 Robert McQueen * python/service.py: s/sucessful/successful/ so we're allocating to and reading from the same variable. Oops. 2005-11-30 John (J5) Palmieri * Released 0.60 2005-11-30 John (J5) Palmieri * test/qt/Makefile.am: build from srcdir * qt/qtconnection.cpp (requestName): Changed PROHIBIT_REPLACE to ALLOW_REPLACE Note - this code is wrong and needs to be fixed by the Qt binding developers. The flags should be treated as bitfields and not enums. * qt/qtconnection.h: Change ProhibitReplace to AllowReplace 2005-11-30 John (J5) Palmieri * dbus/dbus-list.c (_dbus_list_insert_after_link, _dbus_list_insert_after, link_after): remove #ifdef DBUS_BUILD_TESTS since we use these methods in production code 2005-11-30 John (J5) Palmieri * dbus/dbus-connection.c (dbus_connection_read_write): Add new method for getting messages off the bus in the absence of a mainloop. This method is much like dbus_connection_read_write_dispatch except it does not dispatch the messages to a registered filter function. Instead it allows a developer to process messages by directly popping them off the bus. 2005-11-30 John (J5) Palmieri * bus/desktop-file.c (parse_key_value): Ignore locales allowing the parser to continue instead of returning error (bus_desktop_file_load): Do not free parser data when parse_section_start or parse_key_value fails because it was already freed by parser_free (patch from Carlos Garcia Campos ) 2005-11-30 John (J5) Palmieri * dbus/dbus-auth.c, dbus/dbus-connection.c, dbus/dbus-keyring.c, dbus/dbus-server-debug-pipe.c, glib/dbus-binding-tool-glib.c glib/dbus-glib-tool.c, glib/dbus-gparser.c, glib/dbus-gproxy.c test/test-segfault.c, test/test-utils.c, test/glib/test-dbus-glib.c, tools/dbus-cleanup-sockets.c tools/dbus-launch.c, tools/dbus-tree-view.c, tools/dbus-viewer.c: Various cleanup of dead code and compiler warnings (patch from Kjartan Maraas ) 2005-11-30 John (J5) Palmieri * glib/dbus-gmain.c (connection_setup_add_watch): plugged a leak (patch from Carlos Garnacho Parro 2005-11-27 Robert McQueen * python/dbus_bindings.pyx: Repair my previous commit which reverted part of the preceding one. Oops. Merge patch by Johan Hedberg to fix marshalling of 16-bit integer values on big-endian platforms. * test/python/test-client.py: Add some 16-bit integers to the test values. 2005-11-27 Carlos Garcia Campos * glib/dbus-gobject.c: Append a GValue instead of a basic type in method return message for property getters 2005-11-27 Robert McQueen * python/dbus_bindings.pyx: Fix a bug where doing a strict append with type v of an instance of dbus.Variant(foo, type='x') caused it to be boxed twice before sending over the bus. * python/dbus_bindings.pyx, python/service.py, test/python/test-client.py: Update the constants for the new request_name flags, and update comments/test cases now that queueing is the default action. 2005-11-22 John (J5) Palmieri * configure.in: - Change version to 0.60 for impending release - upped the sonames because of ABI and API breakage 2005-11-22 John (J5) Palmieri * configure.in: Add test/name-test/Makefile to the generated Makefile list * dbus/dbus-shared.h (#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT): New flag which replaces DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT (#define DBUS_NAME_FLAG_DO_NOT_QUEUE): New flag for specifying not to queue an ower if it can't be the primary owner * bus/bus.h: Add new internal BusOwner struct * bus/driver.c (bus_driver_handle_hello): Send flags (0 for default) to bus_registry_ensure and don't set the prohibit_replacement flag since they are now set per BusOwner and not per name. (bus_driver_handle_list_queued_owners): bus method (ListQueuedOwners) that returns the list of connections in a name's connection queue * bus/services.c (struct BusService): remove prohibit_replacement field (struct BusOwner): new struct for keeping track of queued connections and their associated flags for the queue (struct BusRegistry): add a BusOwner memory pool (bus_registry_new): initialize the BusOwner memory pool (bus_registry_unref): free the BusOwner memory pool (_bus_service_find_owner_link): new internal method for searching the queue for a specific connection (bus_owner_set_flags): new method for adding setting the flags on a bus owner (bus_owner_new): new method that creates a BusOwner object from the pool and sets its flags (bus_owner_ref, bus_owner_unref): ref counting for BusOwner objects (bus_registry_ensure): Add the flags parameter (bus_registry_acquire_service): Switch from using raw connections to using the BusOwner struct Add new state machine for dealing with the new set of flags (bus_registry_set_service_context_table, struct OwnershipCancelData, cancel_ownership, free_ownership_cancel_data, add_cancel_ownership_to_transaction, struct OwnershipRestoreData, restore_ownership, free_ownership_restore_data, add_restore_ownership_to_transaction): Switch to using BusOwner instead of raw connections (bus_service_add_owner): Add flags parameter Switch to using BusOwner instead of raw connections Add state machine for dealing with the new set of flags (bus_service_swap_owner): Swaps the first and second owners in the queue. Used to make sure proper signals are sent when a service looses or gains primary ownership. We never insert an owner at the top of the queue. Instead we insert it in the second position and then swap. (bus_service_remove_owner): Remove the owner from the queue sending out the NameLost and NameOwnerChanged signals if the we were the primary owner (bus_service_get_primary_owners_connection): New method that extracts the connection from the primary owner (bus_service_get_primary_owner): Returns the BusOwner instead of the connection (bus_service_get_allow_replacement): Changed from the old bus_service_get_prohibit_replacement method. Checks the flags of the primary owner and returns if it can be replaced or not (bus_service_set_prohibit_replacement): removed (bus_service_has_owner): returns TRUE if and owner with the specified connection exists in the queue * dbus/dbus-bus.c (dbus_bus_connection_get_unique_name): New helper method that only compiles if tests are enabled. Allows us to get the unique name of a connection so we can check it against the queue when doing regression tests * bus/activation.c (bus_activation_send_pending_auto_activate), bus/dispatch.c (bus_dispatch), bus/driver.c (bus_driver_handle_get_service_owner, bus_driver_handle_get_connection_unix_user, bus_driver_handle_get_connection_unix_process_id, bus_driver_handle_get_connection_selinux_security_context), bus/signals.c (connection_is_primary_owner): use bus_service_get_primary_owners_connection instead of bus_service_get_primary_owner * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket, _dbus_listen_unix_socket): Calculate the length of the socket path and use that instead of using a fixed length which was causing socket names to contain many trailing Nul bytes. * dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c (dbus_g_method_get_sender): New method for extracting the sender from a DBusGMethodInvocation (dbus_g_method_return_get_reply): changed name to dbus_g_method_get_reply (dbus_g_method_return_send_reply): changed name to dbus_g_method_send reply * doc/dbus-specification.xml: New docs that describe how the new queueing system works and talks about the changes to the how we specify socket names * glib/examples/example-service.c, glib/examples/example-signal-emitter.c, glib/examples/statemachine/statemachine-server.c: Changed the RequestName flags to the new system * test/name-test/ (test-names.c, run-test.sh, Makefile.am): New regression test suite for testing various states of the new queueing system 2005-11-15 Robert McQueen * dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c: Patch from Rob Taylor to add two methods, dbus_g_method_return_get_reply and dbus_g_method_return_send_reply, to allow you to get the reply message from a DBusGMethodInvocation, append arbitrary stuff to it, and send it. The GLib bindings can't marshal a return value of something like a(s) if the array is empty - ultimately they should be made to heed the signature of the out arguments as the Python bindings now can, but this is a workable interim solution which might have other applications. 2005-11-15 Robert McQueen * bus/driver.c, bus/services.c, bus/services.h: Add a ReleaseName method to org.freedesktop.DBus to release a bus name or give up waiting in the queue for it. * dbus/dbus-bus.c, dbus/dbus-bus.h, dbus/dbus-shared.h: Add a dbus_bus_release_name method to send the ReleaseName method calls. Add constants for the return values to dbus/dbus-shared.h. * doc/dbus-specification.xml: Document the new ReleaseName method in the specification. * python/dbus_bindings.pyx: Add a low-level python binding for the release name method. * python/exceptions.py, python/service.py: Make freeing BusName objects release the name. Add a NameExistsException, and fix a bug with creating UnknownMethodException. * test/python/test-client.py: Add tests for freeing BusName objects causing names to be released. 2005-11-14 Robert McQueen * python/service.py: Include the traceback in the error reply when we send an exception over the bus. _BEST_ _PATCH_ _EVER_ 2005-11-14 David Zeuthen Patch from Timo Hoenig . * bus/bus.c: I've recently investigated why the automatic reload of configuration files does not work as expected. Currently, reloading configuration files does only work when running dbus-daemon with --nodaemon. If we are running as daemon we're hitting a dnotify bug once we fork the process. We're initializing the dnotify fds before calling fork(). Once the child process forked it does still have the fds (and they still show up in /proc/`pidof dbus-daemon`/fd/) but we're not getting SIGIO as changes are made to the configuration files. The attached patch moves the initialization of the dnotify fds to process_config_postinit(). This is safe for all current code paths and solves the dnotify disfunction. If we're running dbus-daemon as daemon the fds for dnotify are now being initialized after fork() for the child process. * configure.in: The current configure.in check for dnotify probes 'x$target_os' for being 'xlinux-gnu'. I've changed the check to match for 'xlinux', too. Additionally I have adapted the configure option's style to match with the others. 2005-11-14 Robert McQueen * python/decorators.py, python/service.py: Add a new argument to the dbus.service.method decorator called sender_keyword, which if set, specifies the name of an argument which will be provided the bus name of the method caller. * test/python/test-client.py, test/python/test-service.py: Add a method and test to check the sender_keyword functionality. 2005-11-07 John (J5) Palmieri * bus/driver.c (bus_driver_handle_reload_config): Make sure we send an empty reply so blocking calls don't block forever (Patch from Sjoerd Simons ) * AUTHORS: Add Robert McQueen for his work on the Python Bindings and other parts of D-Bus 2005-11-07 Robert McQueen * python/decorators.py: Change emit_signal function to use the signature annotation of the signal when marhsalling the arguments from the service. Fix a bug where the code checking signature length against argument length referenced the wrong variable. * python/introspect_parser.py: Avoid adding the type signature of signal arguments to any methods which occur after them in the introspection data (!) by making the parser a little more careful about its current state. * python/service.py: Remove debug prints from last commit (again :D). * test/python/test-client.py, test/python/test-service.py: Add test signals with signature decorators to test the strict marshalling code gives errors at the right time. Could do with checking the signals actually get emitted too, given that the test does nothing with signals at the moment... 2005-11-07 Robert McQueen * python/_dbus.py: Add WeakReferenceDictionary cache of dbus.Bus instances to stop madness of creating new instances representing the same bus connection all the time, rendering any tracking of match rules and bus names quite meaningless. Caught a bug where the private argument to SessionBus() and friends was being passed in as use_default_mainloop by mistake. Still some problems with multiple dbus_binding.Connection instances representing the same low-level connection (eg when you use both SessionBus() and StarterBus() in same process), but it's a lot better now than it was. * python/dbus_bindings.pyx: Add constants with the return values for bus_request_name(). * python/service.py: Store bus name instances in a per-dbus.Bus cache and retrieve the same instances for the same name, so deletion can be done with refcounting. Also now throws some kind of error if you don't actually get the name you requested, unlike previously... * test/python/test-client.py: Add tests for instance caching of buses and bus name objects. 2005-11-04 Robert McQueen * python/dbus_bindings.pyx, test/python/test-client.py: Fix marshalling of boolean values. Add some booleans to the values in the test client. * python/decorators.py, python/service.py: Add an 'async_callbacks' argument to the dbus.service.method decorator, which allows you to name arguments to take two callback functions for replying with return values or an exception. * test/python/test-client.py, test/python/test-service.py: Add test case using asynchronous method reply functions, both return values and errors, and from within both the function itself and from a mainloop callback. * python/decorators.py, python/service.py: Perform checking that the number of method/signal arguments matches the number of types in the signature at class loading time, not when you first introspect the class. * python/service.py: Remove debug print left by the last commit. 2005-11-03 Robert McQueen * python/service.py: Heavy refactoring of method invocation, with hopefully no effect on functionality. Nuked _dispatch_dbus_method_call in favour of a new _message_cb that uses seperate functions for looking up the method to call, marshalling the return values, and sending exceptions as errors, and is easier to follow as a consequence. Fixes some corner cases about returning things that don't match your declared out_signature, allows exceptions to define _dbus_error_name and have it be sent over the bus as the error name, and paves the way for cool stuff like heeding the message no reply flag, asynchronous method implementations, informing the method of the sender, and including backtraces in the error messages. * test/python/test-client.py: Catch and print exceptions thrown in the async callback tests, rather than passing them to the low-level bindings to be ignored in a noisy and frustrating manner. 2005-11-03 Robert McQueen * python/_dbus.py, python/proxies.py, python/service.py: Add __repr__ functions to dbus.Bus, dbus.service.BusName and dbus.service.Object, tweak others to be consistent. * test/python/test-client.py: Tweak output of testInheritance. 2005-10-29 Robert McQueen * python/service.py: Major changes to allow multiple inheritance from classes that define D-Bus interfaces: 1. Create a new Interface class which is the parent class of Object, and make the ObjectType metaclass into InterfaceType. 2. Patch written with Rob Taylor to replace use of method_vtable with code that walks the class's __MRO__ (method resolution order) to behave like Python does when invoking methods and allow overriding as you'd expect. Code is quite tricky because we have to find two methods, the one to invoke which has the right name and isn't decorated with the /wrong/ interface, and the one to pick up the signatures from which is decorated with the right interface. The same caveats apply as to normal multiple inheritance - this has undefined behaviour if you try and inherit from two classes that define a method with the same name but are decorated with different interfaces. You should decorate your overriding method with the interface you want. 3. Replace grungy introspection XML generation code in the metaclass with dictionaries that cope correctly with multiple inheritance and the overriding of methods. This also uses the signature decorations to provide correct introspection data, including the debut appearance of the types of your return values. :D * test/python/test-client.py, test/python/test-service.py: Add a test case to try invoking an method that overrides one inherited from a D-Bus interface class. 2005-10-29 Robert McQueen * python/dbus_bindings.pyx: Tweak 'raise AssertionError' to assert(). Add checking for the end of struct character when marshalling a struct in MessageIter.append_strict. * python/examples/example-service.py, python/examples/gconf-proxy-service.py, python/examples/gconf-proxy-service2.py: Update to use gobject mainloop directly rather than appearing to depend on gtk. * python/test/test-client.py, python/test/test-server.py: Remove obsolete and broken test scripts for old bindings. We have up to date and working tests in test/python/. 2005-10-29 Robert McQueen * python/decorators.py: Add optional arguments to the method and signal decorators to allow you to specify the signature of arguments and return values. Preserve the doc strings of signal functions in the decorated version, for pydoc and friends. * python/dbus_bindings.pyx, python/proxies.py: Replace the parse_signature_block function with an iterable dbus.Signature() type. Fix a bug in MessageIter.append_strict where you could append anything by claiming it was a string. * python/service.py: Use the out_signature decoration on methods to marshal return values, meaning you no longer require dbus.Array() or dbus.Dictionary() to indicate the type when returning empty arrays or dictionaries. Fix a bug where exceptions which are defined in __main__ are not turned into error replies. * test/python/test-client.py, test/python/test-service.py: Add test for correct marshalling of return values according to out_signature. Fix a bug in the async call test where the error_handler is missing a self argument. 2005-10-29 Robert McQueen * glib/Makefile.am, glib/examples/Makefile.am, glib/examples/statemachine/Makefile.am: Merge patch from Ubuntu by Daniel Stone to replace explicit calls to libtool with $(LIBTOOL). * test/python/.cvsignore: Add run-with-tmp-session-bus.conf. * tools/dbus-monitor.1, tools/dbus-monitor.c: Merge dbus-monitor patch from Ubuntu by Daniel Silverstone to allow specifying match rules on the command line. 2005-10-27 Ross Burton * dbus/dbus-marshal-header.c: Remove dead code. * glib/dbus-gobject.c: Stop compiler warning. 2005-10-25 Ross Burton * dbus/dbus-auth.c: * dbus/dbus-server-unix.c: * dbus/dbus-transport-unix.c: * glib/dbus-gmain.c: * glib/dbus-gobject.c: Add some const keywords. 2005-10-25 Ross Burton * doc/dbus-specification.xml: Document the NoReply annotation. * glib/dbus-binding-tool-glib.h: * glib/dbus-binding-tool-glib.c: Respect the NoReply annotation. 2005-10-24 Robert McQueen * python/dbus_bindings.pyx (String, MessageIter): make D-Bus strings derive from unicode instead of str, and encode/decode UTF-8 when marshalling/unmarshalling bus messages * python/introspect_parser.py: encode introspection data as UTF-8 before passing the buffer into libxml2 * test/python/test-client.py: add unicode test strings * test/data/valid-service-files/.cvsignore, test/python/.cvsignore: ignore generated python test files 2005-10-17 John (J5) Palmieri * glib/dbus-gvalue-utils.c (hash_free_from_gtype): handle gdouble and G_TYPE_VALUE_ARRAY (DBUS_TYPE_STRUCT) (gvalue_from_hash_value, hash_value_from_gvalue): handle gdouble * glib/dbus-gvalue.c (dbus_gvalue_to_signature): add missing DBUS_STRUCT_BEGIN_CHAR and DBUS_STRUCT_END_CHAR charaters when constructing struct signatures * python/_dbus.py (Bus): handle private connections using the private keyword in the constructor. defaults to private=False (Bus::close): new method to close a connection to the bus * python/dbus_bindings.pyx (Connection::close): renamed method was previously called disconnect (bus_get): now supports getting a private connection * python/proxies.py (ProxyMethod::__call__): check if ignore_reply keyword is set to True. if it is, execute the method without waiting for a reply (ProxyObject::_introspect_execute_queue): new method for executing all the pending methods that were waiting for the introspect to finish. this is called when introspect either succeeds or fails (ProxyObject::_introspect_error_handler): call queued methods 2005-10-14 John (J5) Palmieri * python/dbus_bindings.pyx (MessageIter::append_strict): check for STRUCT_BEGIN not TYPE_STRUCT in indicate we are marshalling a struct * python/service.py (Object::_message_cb): handle exceptions correctly by sending them over the wire to the calling app. This makes sure the client returns immediately instead of waiting the 15 seconds to timeout. * test/python/test-client.py (TestDBusBindings::testBenchmarkIntrospect): Add a test to benchmark how long it takes to introspect a service and call a method which returns a large element (pretty fast) * test/python/test-service.py (TestObject::GetComplexArray): new test method which pushes a lot of data 2005-10-13 John (J5) Palmieri * python/service.py(ObjectType::_reflect_on_signal, _reflect_on_method): reclaim memory outside of the loop and use del istead of just setting the key to None 2005-10-13 John (J5) Palmieri * python/service.py (ObjectType::_reflect_on_signal): Always close signal tag even when there are no arguments 2005-10-13 John (J5) Palmieri * configure.in: Set mono, mono-docs and Qt3 to default to no instead of auto when building. These bindings do not have full time maintainers and will not be supported for the 1.0 release. 2005-10-12 John (J5) Palmieri patches from Michael Krivoruchko : * dbus/dbus-connection.c (_dbus_connection_queue_received_message_link, _dbus_connection_message_sent, _dbus_connection_send_preallocated_unlocked_no_update, _dbus_connection_pop_message_link_unlocked): handle the case when path is NULL when calling _dbus_verbose * configure.in: check for functions getpeerucred and getpeereid * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): provides support of auth EXTERNAL on Solaris 10+ (getpeerucred), FreeBSD 4.6+, OpenBSD 3.0+ and FreeBSD 5.0+ as well as MacOSX 10.2+ (getpeereid). Patch was only tested on Solaris 10 x86 so it might be issues with other platforms (i.e. BSDs and MacOSX) 2005-10-05 John (J5) Palmieri * glib/dbus-gvalue.c (marshal_variant): call _dbus_gvalue_marshal instead of marshal basic so we can handle recursive types in a variant * test/glib/test-dbus-glib.c: Add test for marshaling recurive types in variants * test/glib/test-service-glib.c, test-service-glib.xml (my_object_echo_variant [EchoVariant], my_object_process_variant_of_array_of_ints123 [ProcessVariantOfArrayOfInts123]): Add two test methods * python/introspect_parser.py: New module for parsing introspect data. * python/dbus_bindings.pyx: (various places): when throwing errors fix to use errormsg instead of message local variable because Pyrex can get confused with other message variables (initial patch by Robert McQueen ) (MessageIter::parse_signature_block): new method for getting the next block in a signiture. (MessageIter::append_strict): new method for appending values strictly using the passed in signature instead of guessing at the type (MessageItter:: append_dict, append_struct, append_array): use signatures to marshal children if the signature is available * python/exceptions.py (IntrospectionParserException): new exception * python/proxies.py (ProxyMethod::__call__): Marshal args with introspected signatures if available, else we fall back to the old way of doing things. (ProxyObject::_introspect_reply_handler ): parse introspection data * python/service.py (ObjectType::_reflect_on_method): Properly terminate if there are no args in the reflection data * test/python/test-client.py: add tests for talking with the GLib test server. This gives us better coverage for introspection since python to python will always generate arguments as variants. It also allows us to test the robustness of the GLib bindings and interlanguage communications. 2005-10-03 John (J5) Palmieri * bus/driver.c (bus_driver_handle_introspect): Add signals to the introspect data. (patch from Daniel P. Berrange ) * bus/dispatch.c (check_existent_ping): Add testcase for Ping * dbus/dbus-connection.c (_dbus_connection_peer_filter, _dbus_connection_run_builtin_filters): Changed these to be unlock_no_update functions and call _dbus_connection_send_unlocked_no_update instead of dbus_connection_send to avoid locking errors. * doc/TODO: Removed the make Ping test TODO 2005-09-26 John (J5) Palmieri * dbus/Python.pyx: Fixed memory leaks when throwing errors. We now copy the message from a DBusError and then free the error object befor throwing the error * glib/dbus-glib-tool.c: removed extra comma at the end of the DBusBindingOutputMode enum which was causing a warning. #include so using time_t is explicitly defined 2005-09-26 John (J5) Palmieri * Integrate patches from Lennart Poettering : - dbus/dbus-bus.c (internal_bus_get): new method that take over the heavy lifting of dbus_bus_get and adds the ability to get a private connection to the bus (dbus_bus_get): wrapper to internal_bus_get that provides the same interface as in previous versions (dbus_bus_get_private): new method that is a wrapper to internal_bus_get to get a private connection to the bus - dbus/dbus-bus.h (dbus_bus_get_private): add as a public libdbus interface - dbus-1.pc.in: output system_bus_default_address and sysconfdir variables so apps can use them when compiling 2005-09-23 Harald Fernengel * dbus/qt: New Qt bindings 2005-09-12 Waldo Bastian * dbus/dbus-marshal-validate.c, doc/dbus-specification.xml, test/Makefile.am, test/test-names.c: allow hyphens in bus names. 2005-09-11 Mark McLoughlin * test/data/auth/fallback.auth-script: we don't retry the EXTERNAL method when we know its going to fail anymore. 2005-09-11 Mark McLoughlin * dbus/dbus-connection-internal.h: rename (add|remove|toggle)_(watch|timeout) to unlocked() * dbus/dbus-connection.c: ditto. * dbus/dbus-timeout.c, dbus/dbus-transport-unix.c: Update some callers for the renaming. 2005-09-10 Mark McLoughlin * dbus/dbus-auth.c: (record_mechanisms): don't retry the first auth mechanism because we know we're just going to get rejected again. * dbus/dbus-keyring.c: (_dbus_keyring_reload): Fix thinko ... and what a nasty little bugger to track down you were ... * dbus/dbus-connection.c: (_dbus_connection_add_watch), (_dbus_connection_remove_watch): add note about these needing the connection to be locked. (_dbus_connection_get_dispatch_status_unlocked): set status to DATA_REMAINS when we queue the disconnected message. * bus/dispatch.c: (bus_dispatch): fix warning. (check_existent_service_no_auto_start): Expect ChildSignaled error too. (check_existent_hello_from_self): fix another couple of warnings. 2005-09-08 Joe Shaw Patches from James Willcox * mono/Makefile.am: Add Int16.cs and UInt16.cs * mono/DBusType/Array.cs: Handle multidimensional arrays, and support array "out" parameters. * mono/DBusType/Int16.cs, mono/DBusType/UInt16.cs: New files, for 16-bit int support. 2005-09-06 John (J5) Palmieri * Released 0.50 * Patch from Steve Grubb: - bus/activation.c (bus_activation_service_reload_test): clean up some indentation - dbus/dbus-keyring.c (_dbus_keyring_reload): fix conditional - dbus/dbus-message-factory.c (generate_special): fix a couple of buffer overflows in the test suite. This is non critical because it can not be exploited and this code is only run when doing a make check. * Patch from Yaakov Selkowitz: Build fixes for Cygwin - configure.in: Don't check and link against kdecore, only qt headers - dbus/Makefile.am: Add -no-undefined to libdbus_1_la_LDFLAGS - gcj/org/freedesktop/dbus/Makefile.am: add libdbus_gcj_1_la_LDFLAGS = -no-undefined - glib/Makefile.am: Add -no-undefined to libdbus_glib_1_la_LDFLAGS and $(DBUS_GLIB_LIBS) to dbus_binding_tool_LDADD - qt/Makefile.am: Add -no-undefined to libdbus_qt_1_la_LDFLAGS - tools/Makefile.am: Add platform extentions to binaries (i.e. .exe on windows) * configure.in: - Make it so if no suitable version of python is found we only disable building python instead of exiting the configure script - Require version 2.4 of glib for glib bindings - Up version to 0.50 * python/__init__.py: Sync version with libdbus to (0,50,0) 2005-09-05 Olivier Andrieu * dbus/dbus-object-tree.c (find_subtree_recurse): a couple of optimizations (bug #710): - do a binary search in the tree - insert a new child at the right place directly, no need for qsort anymore - do the "double alloc" thing when allocating children 2005-08-31 John (J5) Palmieri * python/Makefile.am: Break on pyrexc errors instead of ignoring them * python/dbus_bindings.pyx: Memory management foo (global): remove hacky _user_data_references global list (GIL_safe_cunregister_function_handler): userdata now stuffed into tuples. Unref user_data (GIL_safe_cmessage_function_handler): userdata now stuffed into tuples (Connection::__del__): Remove and replace with __dealloc__ method (Connection::add_filter): Stuff user_data into a tuple. Use Py_INCREF to keep tuple from being deallocated instead of the global var hack (Connection::register_object_path): Stuff user_data into a tuple. Use Py_INCREF to keep tuple from being deallocated instead of the global var hack (Connection::register_fallback): Stuff user_data into a tuple. Use Py_INCREF to keep tuple from being deallocated instead of the global var hack (GIL_safe_pending_call_notification): Don't unref the message because it gets unreffed when going out of scope. Py_XDECREF the user_data (PendingCall::__del__): Remove and replace with __dealloc__ method (PendingCall::set_notify): ref the pending call because we will need it to stick around for when the notify callback gets called (Message::__del__): Remove and replace with __dealloc__ method * python/dbus_glib_bindings.pyx (init_gthreads): Changed to gthreads_init to match up with the dbus call * python/glib.py (init_threads): Changed to threads_init to match up with gobject.threads_init(). init_threads is kept for backwards compat but will most likely be deprecated in the future * test/python/test-client.py: - revamp to use Python's unittest functionality - add async call tests - setup threads in glib and dbus so we make sure locks are working 2005-08-30 John (J5) Palmieri * python/dbus_bindings.pyx (_pending_call_notification, cunregister_function_handler, cmessage_function_handler): All callback functions have been rearranged to workaround a bug in Pyrex when working with the GIL which is Python's global lock when dealing with threads. They have been split into a wrapper function (which assumes the name of the old function) and a _GIL_safe_ function which contains the functionality of the old function. This ensures that Pyrex does not write code the lock is released. 2005-08-30 John (J5) Palmieri * python/dbus_bindings.pyx (_pending_call_notification): Obtain the GIL global lock when calling back into Python 2005-08-29 John (J5) Palmieri * Release 0.36.2 * Add Havoc's patch that never got applied to HEAD (Bug #2436): * bus/policy.c (bus_policy_allow_user): change default "user is allowed" to be "user has same uid as the bus itself"; any allow/deny rules will override. * bus/session.conf.in: don't allow all users, since now by default the user that ran the bus can connect. 2005-08-26 Colin Walters * tools/dbus-print-message.c (print_message): Flush stdout after printing a message, so that redirecting to a file, then hitting Ctrl-C works. 2005-08-25 John (J5) Palmieri * python/dbus_bindings.pyx: Tracked down a major memleak and fixed it (EmptyMessage): new class that subclasses Message. This is a workaround to a Pyrex bug that fails to call __del__ when the Message object goes out of scope. For some reason subclassing Message fixes this bug (Bus::send_with_reply_and_block): use EmptyMessage instead of Message - s/Message(_create=0)/EmptyMessage everywhere else * test/python/test-{server|client}.py: add the python/.libs directory to the lookup path so dbus_bindings and dbus_glib_bindings don't get picked up from the system 2005-08-25 Colin Walters * glib/dbus-gproxy.c (dbus_g_proxy_call): Doc update, thanks to Ryan Lortie for the suggestion. 2005-08-24 John (J5) Palmieri * test/python: Add python regression test * configure.in: Add test/python/Makefile * test/Makefile.am: Add the python directory to SUBDIRS 2005-08-24 John (J5) Palmieri * Release 0.36.1 * python/_dbus.py: (Interface::connect_to_signal): propigate keywords for match on args (Bus::add_signal_receiver): Fix typo s/dbus_inteface/dbus_interface * python/proxies.py (ProxyObject::connect_to_signal): propigate keywords for match on args * Makefile.am: point everything to pyexecdir since python borks on multilib 2005-08-23 John (J5) Palmieri * Release 0.36 2005-08-23 Colin Walters * test/glib/Makefile.am: Don't multiply-define EXTRA_DIST. 2005-08-23 John (J5) Palmieri * python/dbus_glib_bindings.pyx: reorder imports and c definitions to fix some wranings. We now use dbus_bindings.DBusConnection instead of defining DBusConnection ourselves. 2005-08-18 John (J5) Palmieri * python/dbus.pth: New path file to fix up problems when installing c libraries to lib64 and python files to lib. * python/Makefile.am: install dbus.pth in the correct spot 2005-08-17 John (J5) Palmieri * ChangeLog: clean up my last entry a bit * doc/introspect.xsl: New stylesheet for converting introspection data into browser renderable xhtml. Contributed by Lennart Poettering. * doc/introspect.dtd: Fixups in the introspect format from Lennart Poettering. * doc/dbus-tutorial.xml: - Add Colin Walter to the Authors section for authoring the GLib section - Add descriptions of the new signature and type functionality in the Python complex type mapping section - Add a sidenote on the new args matching functionality in the Python bindings - Fixed up some of the examples to use the gobject.MainLoop instead of gtk.main * python/_dbus.py: (Bus::_create_args_dict): New. Converts a hash of arg matches to a more useable format (Bus::add_signal_receiver): add a **keywords parameter for catching arg match parameters (Bus::remove_signal_receiver): add a **keywords parameter for catching arg match parameters * python/matchrules.py: (MatchTree::exec_matches): Check for arg matches (SignalMatchRule::add_args_match): New method (SignalMatchRule::execute): Added args_list parameter as an optimization so we don't have to marshal the args more than once (SignalMatchRule::match_args_from_list): New method that checks to see if the rule's arg matches match an argument list. Only arguments set in the rule are checked. (SignalMatchRule::match_args_from_rule): New method that checks to see if the rule's arg matches match another rule's. All args have to match in order for this method to return true. If either rule has more args then it is not a match. (SignalMatchRule::is_match): Add args match (SignalMatchRule::repr): Add args to the final output if they exist 2005-08-17 Ross Burton * glib/dbus-gproxy.c: (dbus_g_proxy_call_no_reply): unref the message once sent. (dbus_g_proxy_call): protect against NULL proxy. 2005-08-16 John (J5) Palmieri * python/__init__.py: Version updated (0, 43, 0) * python/dbus_bindings.pyx: - Fixed type objects to have self passed into __init__ - Added the Variant type - Add the ability to specify types or signatures for Array, Variant and Dictionary (Connection::send_with_reply_handlers): return a PendingCall object (_pending_call_notification): handle the case when an error is returned without an error message in the body (MessageIter::get_boolean): return True or False instead of an integer (MessageIter::python_value_to_dbus_sig): add direct checking of types and add checks for objects with embeded signatures or types (Array, Variant and Dictionary) (MessageIter::append_byte): handle case when the value is a dbus.Byte (MessageIter::append_dict): handle embeded types or signatures (MessageIter::append_array): handle embeded types or signatures (MessageIter::append_variant): new method * python/proxies.py: (DeferedMethod): New. Dummy executable object used when queuing calls blocking on introspection data (ProxyMethod::__call__): add the timeout keyword for specifying longer or shorter timeouts for method calls (ProxyObject): Add first pass at an introspection state machine (ProxyObject::__init__): Add introspect keyword for turing off an on introspection. (ProxyObject::_Introspect): Internal Introspect call that bypasses the usual mechanisms for sending messages. This is to avoid a deadlock where the Intospect call would be queued waiting for the Introspect call to finish ;-) (ProxyObject::_introspect_reply_handler): New. This method is called when introspection returns with no error (ProxyObject::_introspect_error_handler): New. This method is called when introspection encounters an error (ProxyObject::__getattr__): Code to handle different introspection states. Queue async calls or block blocking calls if we are introspecting. Pass through as normal if we are not or are done with introspecting. * python/service.py: Import signal and method from decorators.py * python/types.py: Add Variant type 2005-08-16 Colin Walters * glib/dbus-gobject.c (dbus_set_g_error): Don't lose if the DBusError message is NULL. 2005-08-09 Havoc Pennington * dbus/dbus-errors.c: apply patch from Timo Teras to make a malloc'd copy of the name parameter 2005-08-09 Havoc Pennington * dbus/dbus-message.c (dbus_message_set_reply_serial): print warning if the reply serial is set to 0 2005-08-04 Colin Walters * glib/dbus-gvalue-utils.h (_dbus_g_type_specialized_builtins_init) (dbus_g_type_is_fixed, dbus_g_type_fixed_get_size) (dbus_gvalue_set_from_pointer, dbus_g_hash_table_value_foreach) (dbus_g_hash_table_insert_values, dbus_g_hash_table_insert_steal_values) (dbus_gtype_is_valid_hash_key, dbus_gtype_is_valid_hash_value) (dbus_g_hash_func_from_gtype, dbus_g_hash_free_from_gtype) (dbus_g_hash_equal_from_gtype, dbus_gvalue_stor, dbus_gvalue_take): * glib/dbus-gvalue.h (dbus_g_value_types_init) (dbus_gvalue_demarshal, dbus_gvalue_demarshal_variant) (dbus_gvalue_demarshal_message, dbus_gvalue_marshal): Prefix name with _ to ensure they're not exported. All callers updated. * glib/dbus-gvalue.c (typecode_to_gtype) (dbus_typecode_maps_to_basic, basic_typecode_to_gtype) (signature_iter_to_g_type_dict) (signature_iter_to_g_type_array) (dbus_gtype_from_signature_iter, dbus_gtype_from_signature) (dbus_gtypes_from_arg_signature): Move to dbus-gsignature.c. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_type_specialized_builtins_init instead of dbus_g_value_types_init. (dbus_binding_tool_output_glib_client): Ditto. * glib/Makefile.am (DBUS_GLIB_INTERNALS): Add dbus-gsignature.c and dbus-gsignature.h * test/glib/test-service-glib.c (my_object_rec_arrays): Delete unused variable. 2005-08-03 Colin Walters * glib/dbus-gobject.c: Add tests on hardcoded object info; this should catch any incompatible changes accidentally made. 2005-08-03 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): fix typo, from Julien Puydt * bus/connection.c (bus_connection_disconnected): we were always doing a wait_for_memory due to a buggy loop, found by Timo Hoenig 2005-08-01 Colin Walters Patch from Joe Markus Clarke: * glib/dbus-gidl.c (property_info_unref, arg_info_unref): Fix use-after-free. 2005-08-01 Colin Walters Patch from Joe Markus Clarke: * tools/dbus-send.c (main): Don't use C99 style initializers (bug #3933). 2005-08-01 Colin Walters Patch from Joe Markus Clarke: * glib/dbus-gvalue.c (dbus_g_value_types_init): * glib/dbus-gvalue-utils.c (dbus_g_type_specialized_builtins_init) * glib/dbus-gobject.c (write_interface): Don't use C99 style initializers (bug #3933). 2005-07-31 Havoc Pennington * tools/dbus-viewer.c (load_child_nodes): fix invocation of dbus_g_proxy_call, fix from Piotr Zielinski bug #3920 2005-07-30 Havoc Pennington * fix a bunch of Doxygen warnings and mistakes 2005-07-30 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_string_parse_uint): remove #ifdef DBUS_BUILD_TESTS since it's now used in production code 2005-07-29 Havoc Pennington * test/glib/test-profile.c (write_junk): initialize the junk buffer so valgrind doesn't have a breakdown 2005-07-29 Havoc Pennington * bus/signals.c (bus_signals_test): add match_rule_equal() tests (match_rule_matches): remove unused arg (test_matching): add tests for match_rule_matches() * bus/signals.c (bus_match_rule_parse_arg_match): add ability to do arg0='foo' arg5='bar' in the match rules (match_rule_matches): don't match if the arg0='foo' doesn't match. * dbus/dbus-protocol.h (DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER): add this 2005-07-29 Ross Burton * dbus/dbus-connection.c: Don't create a DBusCondVar which is never used. 2005-07-27 Ross Burton * dbus/dbus-message.c: Reduce the size of the maximum cached message to 10K. 2005-07-25 Ross Burton * glib/dbus-gproxy.c: Remove matches when all proxies are unregistered. 2005-07-24 Colin Walters * glib/dbus-gvalue.c (signature_iter_to_g_type_array): Don't require typedata; recursive arrays won't have it. * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Add recursive arrays tests. 2005-07-20 John (J5) Palmieir * python/_dbus.py, _util.py, decorators.py, extract.py, matchrules.py. proxies.py, service.py: Cleanup of code after running it through the pyflakes code checker mostly dealing with undefined names. (Bug #3828, Patch from Anthony Baxter ) 2005-07-17 John (J5) Palmieri * NEWS: Update to 0.35.2 2005-07-17 John (J5) Palmieri * python/_dbus.py: Remove import of the dbus.services module as it no longer exists (patch from Dimitur Kirov) * python/service.py (Object::__init__): Fixed typo s/name/bus_name (patch from Dimitur Kirov) * python/examples/example-signal-emitter.py: import dbus.glib to get the main loop and use glib mainloop instead of gtk so X doesn't have to be running. * python/examples/example-signal-recipient.py: import dbus.glib to get the main loop and use glib mainloop instead of gtk so X doesn't have to be running. Import the decorators module directly. * test/glib/Makefile.am: Added DIST_EXTRA files that distcheck didn't pick up on but are needed to build * configure.in: upped version to 0.35.2 * bus/driver.c, bus/selinux.c, bus/selinux.h, dbus/dbus-protocol.h: added Colin Walters' SELinux API rename patch from head s/unix sercurity context/selinux security context/ 2005-07-16 John (J5) Palmieri * python/Makefile.am: dbus_binding.pxd.in should be included in EXTRA_DIST not dbus_binding.pxd fix up $(srcdir) hopefully for the last time * NEWS: Update to 0.35.1 2005-07-16 Colin Walters * bus/driver.c (bus_driver_handle_get_connection_selinux_security_context): Renamed from bus_driver_handle_get_connection_unix_security_context. Update for error usage. (message_handlers): Update for renames. * bus/selinux.c (bus_selinux_allows_send): Handle OOM on _dbus_string_init failure correctly. (bus_selinux_append_context): Convert SID to context. Append it as a byte array. (bus_selinux_shutdown): Handle the case where bus_selinux_full_init hasn't been called. * bus/selinux.h: Update prototype. * dbus/dbus-protocol.h (DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN): Renamed from DBUS_ERROR_UNIX_SECURITY_CONTEXT_UNKNOWN. 2005-07-15 Colin Walters * doc/TODO: Add note about convenience wrappers. 2005-07-15 John (J5) Palmieri * NEWS: Update to 0.35 2005-07-15 John (J5) Palmieri * glib/Makefile.am: Add make-dbus-glib-error-switch.sh to EXTRA_DIST so distcheck doesn't fail * glib/examples/Makefile.am: Add example-service.xml and example-signal-emitter.xml to EXTRA_DIST so distcheck doesn't fail * glib/examples/statemachine/Makefile.am: Add statemachine.xml and statemachine-server.xml to EXTRA_DIST so distcheck doesn't fail * python/Makefile.am: Preprend $(srcdir)/ to source files so the compiler looks in the right places during distcheck 2005-07-15 John (J5) Palmieri * glib/example/Makefile.am: Fix a typo which cause make distcheck to fail 2005-07-15 John (J5) Palmieri * python/examples/example-service.py, python/examples/example-signal-emitter.py: Fixed up examples for API changes 2005-07-15 John (J5) Palmieri * python/__init__.py: Upped to version (0,42,0) because of the API change 2005-07-15 John (J5) Palmieri * ChangeLog: fix date in last entry * configure.in, bus/system.conf.in: add the ability to configure the system bus user at compiletime with the --with-dbus-user flag (patch from Kristof Vansant) 2005-07-15 John (J5) Palmieri * bus/dispatch.c, test/test-service.c: Add testcase for sending messages to oneself (TODO item). * python/service.py (class Object): Swap ordering of bus_name and object_path parameters to better support inheritance. * doc/dbus-tutorial.xml: change Python docs to reflect change in parameter ordering and fix the inheritance section. * doc/TODO: remove sending message to oneself TODO item 2005-07-15 Ross Burton * glib/dbus-gproxy.c: Fix a leak when calling methods via the proxy. 2005-07-15 Colin Walters * bus/selinux.c (bus_selinux_append_context): Wrap in HAVE_SELINUX. 2005-07-14 John (J5) Palmieri * python/_dbus.py (Bus::remove_signal_receiver): don't add a callback to the match if none has been passed in * python/matchrules.py (SignalMatchTree::remove): if the rule being matched does not have a callback treat it as a wildcard fix matching logic * doc/dbus-tutorial.xml: Add Python tutorial 2005-07-14 Colin Walters * bus/driver.c (bus_driver_handle_get_connection_unix_security_context): New function. (message_handlers): Add. * bus/selinux.c (bus_selinux_append_context): New function; appends security context to message. * bus/selinux.h: Prototype. * dbus/dbus-protocol.h (DBUS_ERROR_UNIX_SECURITY_CONTEXT_UNKNOWN): New. 2005-07-14 John (J5) Palmieri * bus/activation.c: clean up all tabs to be 8 spaces (bus_activation_activate_service): make sure we clean up if activation fails * bus/dispatch.c: clean up all tabs to be 8 spaces (check_shell_fail_service_auto_start): New function tests to make sure we get fail properly when trying to auto start a service with a faulty command line (check_shell_service_success_auto_start): New function tests to make sure auto started services get the arguments on the command line * test/test-shell-service.c: Added service for testing auto-starting with command line arguments * test/data/valid-service-files/debug-shell-echo-fail.service.in, test/data/valid-service-files/debug-shell-echo-success.service.in: Added service files for testing auto-starting with command line arguments * */.cvsignore: added a bunch of generated files to various .cvsignore files 2005-07-14 Rodrigo Moya * dbus/dbus-shell.[ch]: copy/pasted code from GLib. * dbus/Makefile.am: added new files to build. * bus/activation.c (bus_activation_activate_service): support activation commands with parameters. * test/shell-test.c: added test program for the shell parsing code. 2005-07-13 David Zeuthen * tools/dbus-send.c (append_arg, type_from_name): Also support 16 and 64 bit signed and unsigned parameters 2005-07-13 John (J5) Palmieri * python/.cvsignore: remove dbus_bindings.pyx, add dbus_bindings.pxd * python/service.py (class Name): renamed BusName to make it clearer what the object is for (a name on the bus) * python/examples/example-service.py, python/examples/example-signal-emitter.py: change the Name object to BusName 2005-07-12 Colin Walters Patch from Jim Gettys . * tools/dbus-launch.c: Include sys/select.h. 2005-07-12 John (J5) Palmieri * python/dbus_bindings.pyx.in: removed * python/dbus_bindings.pyx: Added. - Fixed some memleaks (patch from Sean Meiners ) - Broke out the #include "dbus_h_wrapper.h" and put it in its own pxd file (Pyrex definition) - Broke out glib dependancies into its own pyx module * python/dbus_bindings.pdx: Added. - Defines C class Connection for exporting to other modules * python/dbus_glib_bindings.pyx: Added. - New module to handle lowlevel dbus-glib mainloop integration * python/glib.py: Added. - Registers the glib mainloop when you import this module * python/services.py: Removed (renamed to service.py) * python/service.py: Added. - (class Server): renamed Name * python/__init__.py: Bump ro version (0,41,0) -don't import the decorators or service module by default. These now reside in the dbus.service namespace * python/_dbus.py (Bus::__init__): Add code run the main loop setup function on creation * python/examples/example-service.py, python/examples/example-signal-emitter.py: update examples * python/examples/gconf-proxy-service.py, python/examples/gconf-proxy-service2.py: TODO fix these up * doc/TODO: Addition - Added a Python Bindings 1.0 section - added "Add match on args or match on details to match rules" 2005-07-12 Colin Walters * glib/examples/statemachine/Makefile.am (statemachine-server-glue.h) (statemachine-glue.h): * glib/examples/Makefile.am (example-service-glue.h) (example-signal-emitter-glue.h): * glib/Makefile.am (dbus-glib-error-switch.h): Add libtool --mode=execute so we use the built library instead of any installed one. 2005-07-11 Colin Walters * glib/dbus-gvalue.c (struct _DBusGValue): Delete. (dbus_g_value_types_init): Remove assertion. (dbus_g_value_get_g_type, dbus_g_value_open) (dbus_g_value_iterator_get_values, dbus_g_value_get_signature) (dbus_g_value_copy, dbus_g_value_free): Delete unimplemented functions related to DBusGValue. Now we marshal/demarshal structures as GValueArray. (dbus_gtype_from_signature_iter): Return G_TYPE_VALUE_ARRAY for structures. (signature_iter_to_g_type_array): Don't call signature_iter_to_g_type_struct. (signature_iter_to_g_type_struct): Delete. (dbus_gvalue_to_signature): Delete. (dbus_gvalue_to_signature): New function with same name as other one; we can convert structures to signatures. (demarshal_valuearray): New function. (get_type_demarshaller): Use it. (demarshal_recurse): Delete. (marshal_proxy): New function. (marshal_map): Warn if we can't determine signature from type. (marshal_collection_ptrarray): Ditto. (marshal_collection_array): Ditto. (get_type_marshaller): Use marshal_valuearray. (marshal_recurse): Delete. (_dbus_gvalue_test): Add some tests. * dbus/dbus-glib.h (struct _DBusGValueIterator): (dbus_g_value_get_g_type, DBUS_TYPE_G_VALUE) (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Remove prototypes. * glib/dbus-binding-tool-glib.c (dbus_g_type_get_lookup_function): Handle G_TYPE_VALUE_ARRAY. * glib/examples/example-service.c: * glib/examples/example-client.c: Implement GetTuple. * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Add structure tests. 2005-07-10 Colin Walters * doc/TODO: Knock off some GLib items with this patch. * glib/dbus-gvalue-utils.c (_dbus_gtype_can_signal_error) (_dbus_gvalue_signals_error): New functions. * glib/dbus-gvalue-utils.h: Prototype them. * glib/dbus-gobject.c (arg_iterate): Update to handle return vals and change to not output const/retval flags for input args. All callers updated. (invoke_object_method): Refactor to handle return values. Add some more comments in various places. Remove debug g_print. * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_RETURNVAL): New. * glib/dbus-binding-tool-glib.c (dbus_g_type_get_marshal_name): Handle G_TYPE_NONE. (compute_gsignature): New function; refactored from code from compute_marshaller and compute_marshaller_name. Enhance to handle return values and async ops more cleanly. Update for async ops returning NONE instead of BOOLEAN. (compute_marshaller, compute_marshaller_name): Call compute_gsignature and output appropriate string. (generate_glue): Handle return value annotation. Also don't dump constness flag for input arguments. * glib/Makefile.am (DBUS_GLIB_INTERNALS): New variable; contains files shared between installed library and utilities. (libdbus_glib_1_la_SOURCES): Move some stuf into DBUS_GLIB_INTERNALS. (libdbus_gtool_la_SOURCES): Suck in DBUS_GLIB_INTERNALS so the binding tool can access gtype utility functions. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add some tests for return values. 2005-07-09 Colin Walters * glib/dbus-gparser.c (parse_annotation): Add annotations to argument if available, not method. * glib/dbus-gobject.c (arg_iterate): More verbose warnings. (invoke_object_method): First, remove some redundant GValues (object_value, error_value) in favor of working on array directly. Second, rework constness to be less buggy. Now we iterate directly over the argument metadata instead of parallel iterating over output signature and metadata. * glib/dbus-glib-tool.h: Add INVALID_ANNOTATION error. * glib/dbus-binding-tool-glib.c (generate_glue): Barf on const annotation on input args. 2005-07-09 Colin Walters * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_CONST): Define. * glib/dbus-binding-tool-glib.c (generate_glue): Handle Const annotation. * glib/dbus-gobject.c (arg_iterate): Update to parse constval too. (method_dir_signature_from_object_info): Handle arg_iterate change. (write_interface): Ditto. (lookup_object_info): Don't barf if format_version is > 0. (invoke_object_method): Handle arg constness. * glib/dbus-gidl.c (struct ArgInfo): Add annotations. (arg_info_new): Create. (arg_info_unref): Destroy. (arg_info_get_annotations, arg_info_get_annotation) (arg_info_add_annotation): New functions. * glib/dbus-gidl.h: Prototype them. * glib/dbus-gparser.c (parse_annotation): Allow annotations in args, disallow them in properties. (parse_annotation): Handle arg annotations. * test/glib/test-service-glib.xml: * test/glib/test-service-glib.c: Update to make some methods const. 2005-07-08 Colin Walters * test/glib/test-service-glib.xml: * test/glib/test-service-glib.c: * test/glib/test-dbus-glib.c: Test a{sv}. * glib/examples/statemachine/statemachine.c: * glib/examples/statemachine/statemachine-server.c: * glib/examples/statemachine/statemachine-client.c: Fix some bugs, add progress bar, etc. * glib/dbus-gvalue.c (register_array, register_dict): Delete; not needed anymore due to generic array/map marshalling. (dbus_g_value_types_init): Don't register basic arrays or the string/string hash. (dbus_gtype_from_signature_iter): Don't try to recurse into variants. (dbus_gtype_to_signature): Check collection/map before type metadata. (demarshal_garray_basic): Renamed to demarshal_collection_array. (demarshal_ghashtable): Renamed to demarshal_map; fix to use new generic map creation/append functions instead of hash table specifically. (get_type_demarshaller): Handle maps. (demarshal_collection): Dispatch on collection type to either demarshal_collection_ptrarray or demarshal_collection_array. (get_type_marshaller): Handle maps. (marshal_collection): Dispatch collection type to either marshal_collection_ptrarray or marshal_collection_array. (_dbus_gvalue_test): New test. * glib/dbus-gvalue-utils.c (unset_and_free_g_value): New function. (hash_free_from_gtype): Use it to free GValues. (hashtable_append): New function. (ptrarray_append): Fix prototype. (slist_append): Ditto. (_dbus_gvalue_utils_test): Extend tests. * glib/dbus-gtype-specialized.c (dbus_g_type_specialized_init_append): Renamed from dbus_g_type_specialized_collection_init_append. Remove const from value, since we steal it. (dbus_g_type_specialized_map_append): New function. * glib/dbus-gtype-specialized.h: Update prototypes. Add DBusGTypeSpecializedMapAppendFunc. * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run _dbus_gvalue_test. * glib/dbus-gtest.h: Prototype it. 2005-07-08 Ross Burton * dbus/dbus-glib.h: Add DBysGAsyncData for the async bindings. * glib/dbus-binding-tool-glib.c: Re-enable the async bindings. * test/glib/test-dbus-glib.c: Add a test for the generated async bindings. 2005-07-08 Colin Walters * doc/TODO: Update GLib todo bits, also add a post-1.0 TODO for a connection concept. 2005-07-08 Colin Walters * tools/Makefile.am: Kill of print-introspect in favor of using dbus-send --print-reply=literal. * test/glib/test-service-glib.xml: * test/glib/test-service-glib.c (my_object_get_objs): New test for "ao". * test/glib/test-dbus-glib.c (echo_received_cb): Free echo data. (main): Test GetObjs. * glib/examples/statemachine/Makefile.am: * glib/examples/statemachine/sm-marshal.list: * glib/examples/statemachine/statemachine-client.c: * glib/examples/statemachine/statemachine-server.c: * glib/examples/statemachine/statemachine-server.xml: * glib/examples/statemachine/statemachine.c: * glib/examples/statemachine/statemachine.h: * glib/examples/statemachine/statemachine.xml: New example. * glib/examples/example-service.c (main): Move invocation of dbus_g_object_type_install_info earlier, to emphasize it should only be done once. * glib/examples/example-signal-emitter.c (main): Ditto. * glib/examples/Makefile.am (SUBDIRS): Include statemachine. * glib/dbus-gvalue.h (dbus_gtype_to_signature) (dbus_gvalue_marshal): Update prototypes. * glib/dbus-gvalue.c: Update all marshalling functions to take const GValue instead of GValue. (signature_iter_to_g_type_array): Return a GPtrArray for nonfixed types. (dbus_gvalue_to_signature): Update for dbus_gtype_to_signature change. (dbus_gtype_to_signature): Handle generic collecitons and maps. Return a newly-allocated string. (demarshal_proxy, demarshal_object_path, demarshal_object) (demarshal_strv, demarshal_ghashtable): Set error, don't assert if we get the wrong types from message. (get_type_demarshaller): New function, extracted from dbus_gvalue_demarshal. (demarshal_collection): New function, demarshals generic collection. (dbus_gvalue_demarshal): Just invoke result of get_type_demarshaller. Throw error if we don't have one. (marshal_garray_basic): Abort on OOM. (get_type_marshaller): New function, extracted from dbus_gvalue_marshal. (collection_marshal_iterator, marshal_collection): New functions; implements generic marshalling for an iteratable specialized collection. (dbus_gvalue_marshal): Just invoke result of get_type_marshaller. * glib/dbus-gvalue-utils.c (gvalue_from_ptrarray_value): Handle G_TYPE_STRING. (ptrarray_value_from_gvalue): Ditto. (ptrarray_append, ptrarray_free): New functions. (slist_constructor, slist_iterator, slist_copy_elt, slist_copy) (slist_append, slist_end_append, slist_free): New functions. (dbus_g_type_specialized_builtins_init): Add append fuctions for GPtrArray and GSList. Register GSList. (test_specialized_hash, _dbus_gvalue_utils_test): New functions. * glib/dbus-gtype-specialized.h (DBusGTypeSpecializedAppendContext): New. (dbus_g_type_specialized_collection_init_append) (dbus_g_type_specialized_collection_append) (dbus_g_type_specialized_collection_end_append): Prototype. (DBusGTypeSpecializedCollectionVtable): Add append_func and end_append_func. * glib/dbus-gtype-specialized.c (dbus_g_type_specialized_collection_init_append) (dbus_g_type_specialized_collection_append) (dbus_g_type_specialized_collection_end_append): New functions. (dbus_g_type_map_value_iterate): Take const GValue. (dbus_g_type_collection_value_iterate): Ditto. * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run _dbus_gvalue_utils_test. * glib/dbus-gtest.h: Prototype it. * glib/dbus-gproxy.c (dbus_g_proxy_manager_filter): Avoid using uninitialized owner_list. (dbus_g_proxy_begin_call_internal): Move return_if_fail to public API. (dbus_g_proxy_end_call_internal): Update to use error set from dbus_gvalue_demarshal instead of setting it here. (dbus_g_proxy_begin_call): Move return_if_fail here. * glib/dbus-gobject.c (write_interface): Update for dbus_gtype_to_signature returning new string. * configure.in: Add glib/examples/statemachine. 2005-07-08 Joe Shaw * configure.in: Add a configure option, --with-console-auth-dir * dbus/dbus-sysdeps-util.c (_dbus_user_at_console): Use the new setting. Patch from Kay Sievers. 2005-07-06 Colin Walters * dbus/dbus-glib.h (DBusGPendingCall, DBusGPendingCallNotify) (DBUS_TYPE_G_PENDING_CALL, dbus_g_pending_call_get_g_type) (dbus_g_pending_call_ref, dbus_g_pending_call_unref): Delete. (dbus_g_pending_call_set_notify, dbus_g_pending_call_cancel): Delete in favor of dbus_g_proxy_begin_call and dbus_g_proxy_cancel_call. (DBusGProxyCall, DBusGProxyCallNotify): New. (dbus_g_proxy_begin_call): Change prototype to take callback, user data, and destroy function. This replaces dbus_g_pending_call_set_notify. (dbus_g_proxy_cancel_call): Prototype. (DBusGAsyncData): Delete, shouldn't be needed anymore. * glib/dbus-gproxy.c (struct _DBusGProxy): Add call_id_counter and pending_calls map. (struct _DBusGProxyManager): Add bus_proxy member, which is an internal proxy for calls to the bus. Remove pending_nameowner_calls, now the internal proxy keeps track. (dbus_g_proxy_manager_unref): Unref bus proxy, remove reference to pending_nameowner_calls. (got_name_owner_cb): Update prototype, and use dbus_g_proxy_end_call. (got_name_owner_cb): Remove reference to pending_nameowner_calls. (dbus_g_proxy_manager_register): Delete directly libdbus code in favor of using internal proxy. (dbus_g_proxy_manager_unregister): Update to use dbus_g_proxy_cancel_call for any pending GetNameOwner call. (dbus_g_proxy_init): Initialize pending calls map. (dbus_g_proxy_constructor): New. (dbus_g_proxy_class_init): Add get/set property functions, constructor, and add NAME, PATH, and INTERFACE properties. (cancel_pending_call): New function. (dbus_g_proxy_dispose): Iterate over any outstanding calls and cancel them. (dbus_g_proxy_set_property, dbus_g_proxy_get_property): New. (GPendingNotifyClosure): New structure. (d_pending_call_notify, d_pending_call_free): Moved here from dbus-glib.c. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Moved around to satisfy function ordering. (manager_begin_bus_call): New internal function for talking to internal bus proxy. (dbus_g_proxy_new): Construct object using GObjet properties. (dbus_g_proxy_begin_call_internal): Update to take user data, etc. Create closure of same, and insert call into map of pending calls. (dbus_g_proxy_end_call_internal): Take call id instead of pending call. Look up pending call in current set. Remove it when we've completed. (dbus_g_pending_call_end, dbus_g_proxy_end_call_internal): Delete. (dbus_g_proxy_begin_call): Change API to take callback, user data, and destroy function directly. (dbus_g_proxy_end_call): Update to take DBusGProxyCall. (dbus_g_proxy_call): Invoke with NULL callback. (dbus_g_proxy_cancel_call): New function, replaces dbus_g_pending_call_cancel. * glib/dbus-gparser.c (validate_signature): Fix call to dbus_set_g_error. * glib/dbus-gobject.c (dbus_g_object_type_dbus_metadata_quark): New quark for attaching metadata to GType. (info_hash): Delete. (lookup_object_info): Look up using quark. (dbus_g_object_type_install_info): Check that a type is classed, not that it's an object. Also just install type data using quark instead of using global hash. * glib/dbus-glib.c (dbus_g_pending_call_ref) (dbus_g_pending_call_unref, dbus_pending_call_get_g_type) (GPendingNotifyClosure): Delete. (d_pending_call_notify, d_pending_call_free): Move to dbus-gproxy.c. (dbus_g_pending_call_set_notify, dbus_g_pending_call_cancel): Delete. * glib/dbus-binding-tool-glib.c (generate_client_glue): Disable async client method generation until we can fix it... * tools/dbus-viewer.c (load_child_nodes): Use dbus_g_proxy_call. (load_from_service_thread_func): Ditto. * tools/dbus-names-model.c (struct NamesModel): Hold DBusGProxyCall. (have_names_notify): Update prototype, use dbus_g_proxy_cancel_call. (names_model_reload): Update for new dbus_g_proxy_begin_call API. * tools/dbus-monitor.c (filter_func): Update for print_message API change. * test/glib/test-dbus-glib.c: Add more tests for async invocations. Update many begin_call/end_call pairs to just use dbus_g_proxy_call. * tools/dbus-send.c (main): Add --print-reply=literal mode. This allows us to dump print-introspect.c. * tools/dbus-print-message.h (print_message): Add literal argument to print_message which is intended to allow printing arguments without metadata like "string=". * tools/dbus-print-message.c (print_iter): Add literal argument. (print_message): Allow printing string messages literally. 2005-07-05 Colin Walters * glib/dbus-gproxy.c (marshal_dbus_message_to_g_marshaller): Remove value refcount leak, original patch from Jorn Baayen . Also remove useless extra value in favor of prepending to value array directly. 2005-07-02 Colin Walters * glib/dbus-gmain.c (_dbus_gmain_test): Fix test. 2005-07-01 Colin Walters Patch from Jonathan Matthew * glib/dbus-gvalue.c (basic_typecode_to_gtype): Fix return type. (dbus_g_value_types_init): Marshal G_TYPE_CHAR as DBUS_TYPE_BYTE, G_TYPE_LONG as DBUS_TYPE_INT32, G_TYPE_ULONG as DBUS_TYPE_UINT32, and G_TYPE_FLOAT as DBUS_TYPE_DOUBLE. 2005-06-30 Colin Walters * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Update tests for new error setting bits, also add async tests (patch from Ross Burton). * test/glib/Makefile.am (test_service_glib_LDADD): Add DBUS_GLIB_THREADS_LIBS. * glib/dbus-gproxy.c (get_name_owner) (dbus_g_pending_call_end_valist): Ditto. * glib/dbus-gobject.c (error_metadata): New mapping from GError domain (GQuark) to DBusGErrorInfo. (gerror_domaincode_to_dbus_error_name): Attempt to look up error quark in error_metadata. Take message interface as default error message interface. (gerror_to_dbus_error_message): Pass message interface. (dbus_set_g_error): Resurrected. (dbus_g_error_info_free): New function. (dbus_g_object_type_install_info): Use g_type_class_ref instead of _peek to actually create the object class if it hasn't been created yet. (dbus_g_error_domain_register): New function. * glib/dbus-gmain.c (dbus_g_bus_get): Switch to dbus_set_g_error. * glib/dbus-gparser.c (validate_signature): Ditto. * dbus/dbus-glib.h (dbus_g_error_set): Delete. (dbus_g_error_domain_register): Prototype. * glib/dbus-glib.c (dbus_g_error_set): Delete. Update tests. 2005-06-29 Colin Walters * dbus/dbus-glib.h: Delete DBUS_TYPE_G_PROXY_ARRAY. Add DBUS_TYPE_G_OBJECT_PATH. * glib/dbus-gvalue.c (dbus_g_value_types_init): Remove marshallers for G_TYPE_OBJECT and DBUS_TYPE_G_PROXY_ARRAY (the latter should be handled more generically). Add DBUS_TYPE_G_OBJECT_PATH. (dbus_g_object_path_get_g_type): New function. (dbus_gtype_from_signature_iter): Map DBUS_TYPE_OBJECT_PATH to DBUS_TYPE_G_OBJECT_PATH by default. (demarshal_proxy): Remove unused name variable. (demarshal_object_path, marshal_object_path): New functions. (demarshal_proxy_array, marshal_proxy_array): Delete. * glib/dbus-binding-tool-glib.c (dbus_g_type_get_c_name): Map DBUS_TYPE_G_OBJECT_PATH to char *. (dbus_g_type_get_lookup_function): Map builtin DBUS_TYPE_G_OBJECT_PATH. * test/glib/test-dbus-glib.c * test/glib/test-service-glib.c (my_object_objpath): Adapt tests to new object path marshalling. 2005-06-29 John (J5) Palmieri * configure.in: force check for Python >= 2.4 2005-06-29 Colin Walters Patch from Ross Burton * glib/dbus-gobject.c (invoke_object_method): Unset object value in all cases, not only in async case. 2005-06-29 Colin Walters * glib/dbus-gproxy.c (struct _DBusGProxy): Add new member name_call for keeping track of any outgoing GetNameOwner call. Also add for_owner and associated. (struct _DBusGProxyManager): Add owner_names, which is hash table that maps a base name to a list of names it owns (that we're interested in). Add pending_nameowner_calls which is a list of all outstanding GetNameOwner; avoids us having to iterate over every proxy. Add unassociated_proxies which keeps track of name proxies with no associated name owner. (dbus_g_proxy_manager_unref): Destroy owner_names. (struct DBusGProxyNameOwnerInfo): New struct for keeping track of name refcounts. (find_name_in_info, name_owner_foreach) (dbus_g_proxy_manager_lookup_name_owner, insert_nameinfo) (dbus_g_proxy_manager_monitor_name_owner) (dbus_g_proxy_manager_unmonitor_name_owner) (unassociate_proxies, dbus_g_proxy_manager_replace_name_owner): New functions; they manipulate the owner_names mapping. (got_name_owner_cb): New function. (get_name_owner): New function, extracted from dbus_g_proxy_new_for_name_owner. (dbus_g_proxy_manager_register): For now we need to keep track of all NameOwnerChanged. Also if the proxy is for a name, if we don't already know the name owner, queue a new GetNameOwner request and add it to our list of unassociated proxies. Otherwise inc the refcount. (dbus_g_proxy_manager_unregister): If this proxy is for a name, cancel any pending GetNameOwner call, etc. (dbus_g_proxy_manager_filter): Handle NameOwnerChanged. Also use the owner_names mapping to look up the current names for the signal source, and dispatch to any proxies for that name. (dbus_g_proxy_new): Initialize new members. (dbus_g_proxy_new_for_name): Delete unused proxy variable. (dbus_g_proxy_new_for_name_owner): Use get_name_owner. (dbus_g_pending_call_end_valist): New function, extracted from dbus_g_proxy_end_call_internal. Useful when we don't have a proxy but want to use the GLib infrastructure. Also note how many arguments in reply were over. (dbus_g_pending_call_end): New function, just call dbus_g_pending_call_end_valist. (dbus_g_proxy_end_call_internal): Just call dbus_g_pending_call_end_valist. * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Fix lookup of builtin marshaller for STRING_STRING_STRING. * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Extend tests to cover name proxies, destruction of owner proxies, etc. * glib/examples/example-signal-recipient.c (dbus_g_proxy_new_for_name_owner): Create a name proxy. * tools/dbus-send.c (main): Print D-BUS error name in addition to message. 2005-06-28 John (J5) Palmieri * python/dbus_bindings.pyx.in (cunregister_function_handler, cmessage_function_handler): Patch from Anthony Baxter fixes threading problems by using the Py_GILState_Ensure/Release to synchronize with the python runtime. 2005-06-28 Ray Strode * dbus/dbus-spawn.c (_dbus_babysitter_unref): kill babysitter helper process on last unref, bug #2813. 2005-06-27 Colin Walters * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Test hash table signal emitting. * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Convert types to their fundamental basis types, since this is what marshallers operate on. Also add an entry for VOID__BOXED. (dbus_g_object_register_marshaller_array): Convert to fundamental. 2005-06-26 Havoc Pennington * doc/dbus-tutorial.xml: fix names of interface/service/path, fix from Don Park 2005-06-26 Colin Walters * glib/dbus-glib.c (dbus_set_g_error): Delete. (dbus_g_error_set): New public function from its ashes; used by both service-side method implementation and GLib bindings internals. (dbus_g_error_has_name, dbus_g_error_get_name): New function. (_dbus_glib_test): Add some tests. * test/glib/test-dbus-glib.c (main): Test dbus_g_error_has_name. * test/glib/test-service-glib.c (my_object_throw_error): Use dbus_g_error_set. * glib/dbus-gobject.c (gerror_to_dbus_error_message): Handle errors thrown by dbus_g_error_set. * glib/dbus-gmain.c (dbus_g_bus_get): Change to dbus_g_error_set. * glib/dbus-gparser.c (validate_signature): Ditto. * glib/dbus-gproxy.c (dbus_g_proxy_new_for_name_owner) (dbus_g_proxy_end_call_internal): Ditto. * glib/Makefile.am: Generate dbus-glib-error-switch.h, which converts DBUS_ERROR_x to DBUS_GERROR_x. (libdbus_glib_1_la_SOURCES, BUILT_SOURCES, CLEANFILES): Add it. * doc/TODO: Remove error TODO. * doc/dbus-tutorial.xml: Update with documentation about error handling. * dbus/make-dbus-glib-error-enum.sh: Tighten up regexp to make sure we only change DBUS_ERROR to DBUS_GERROR, not all ERROR to GERROR. Also add DBUS_GERROR_REMOTE_EXCEPTION. 2005-06-22 Colin Walters Patch from Ross Burton * glib/dbus-gobject.c (dbus_g_method_return): Free out_sig. 2005-06-20 Colin Walters * configure.in: Add glib/examples. * glib/Makefile.am: Add examples/ * glib/examples/.cvsignore * glib/examples/Makefile.am * glib/examples/example-client.c * glib/examples/example-service.c * glib/examples/example-service.xml * glib/examples/example-signal-emitter.c * glib/examples/example-signal-emitter.xml * glib/examples/example-signal-recipient.c: New files; GLib binding examples, ported from python/examples. 2005-06-20 Colin Walters * dbus/dbus-glib.h: * glib/dbus-gproxy.c: Rename dbus_g_proxy_invoke to dbus_g_proxy_call. * glib/dbus-binding-tool-glib.c: * doc/dbus-tutorial.xml: * test/glib/test-dbus-glib.c: Update for rename. 2005-06-20 Colin Walters Patch suggested by Ross Burton * glib/dbus-gobject.c (export_signals): Free signal name. (g_value_init): Use G_VALUE_NOCOPY_CONTENTS to plug memory leak. Add a bit of documentation. (dbus_g_method_return_error): Free context, and note we do so. 2005-06-18 Murray Cumming * dbus/dbus-glib.h: * glib/dbus-gobject.c: * glib/dbus-gproxy.c: * glib/dbus-gvalue.c: Predeclare structs as typedef struct _Something Something instead of typedef struct Something Something, so we can redeclare the prototypes. Other GNOME libraries do this already. 2005-06-17 Colin Walters * tools/dbus-names-model.c (have_names_notify): Fix call to dbus_g_proxy_end_call. 2005-06-17 Colin Walters * glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): Don't spew warnings if we get malformed remote signals. * glib/dbus-gobject.c (propsig_iterate): New function. (lookup_object_info): New function, extracted from lookup_object_and_method. (introspect_properties, introspect_signals): Delete; these are merged into write_interface. (write_interface): Write out signals and properties here; dump the org.gtk.object stuff and use the interface given in the introspection data blob. Also fix up property XML. (lookup_values): New function. (introspect_interfaces): Gather a mapping from interface to a list of its methods, signals, and properties, then write out each interface. (lookup_object_and_method): Use lookup_object_info. (struct DBusGSignalClosure): Add interface. (dbus_g_signal_closure_new): Add interface. Don't dup signame; we can just use the constant data. (dbus_g_signal_closure_finalize): Don't free signal name. (signal_emitter_marshaller): Use interface from signal closure. (export_signals): Only export signals mentioned in introspection blob. (dbus_g_connection_register_g_object): Warn if we have no introspection data for an object. (funcsig_equal): Remove unused variable. (dbus_g_object_register_marshaller): Take varargs instead of list. (dbus_g_object_register_marshaller_array): New function, extracted from old dbus_g_object_register_marshaller. * glib/dbus-binding-tool-glib.c (struct DBusBindingToolCData): Add signals and property data. (write_quoted_string): New function, extracted from generate_glue. (generate_glue): Write signals and properties to introspection blob. * dbus/dbus-glib.h (struct DBusGObjectInfo): Include exported_signals and exported_properties. (dbus_g_object_register_marshaller): Update prototype. (dbus_g_object_register_marshaller_array): Prototype. * test/glib/test-dbus-glib.c: Extend testing to cover new signals. * test/glib/test-service-glib.c: Add new test signals and method to emit them. * test/glib/test-service-glib.xml: Add some test signals. * test/glib/Makefile.am (BUILT_SOURCES): Add my-object-marshal.c and my-object-marshal.h (test_service_glib_SOURCES, test_dbus_glib_SOURCES): Add my-object-marshal.c. (my-object-marshal.c, my-object-marshal.h): Implement. * test/glib/.cvsignore: Update. * doc/TODO: Remove two GLib TODO items fixed by this patch. 2005-06-16 Colin Walters * doc/TODO: Update for GLib bindings. 2005-06-16 Colin Walters * glib/dbus-binding-tool-glib.c: * glib/dbus-gobject.c: * glib/dbus-gproxy.c: Add Nokia copyright; Patch from Ross Burton, for his GLib bindings work. 2005-06-16 Colin Walters * glib/dbus-gobject.c (funcsig_hash, funcsig_equal): Use n_params to iterate instead of walking to G_TYPE_INVALID. Patch based on a patch from Ryan Gammon. 2005-06-16 Colin Walters * bus/bus.c (bus_context_new): Set parser to NULL after we unref it (Patch from Chris Boscolo, #2174). 2005-06-16 Colin Walters * python/dbus_bindings.pyx.in: Import size_t, __int64_t, __uint64_t, and __signed. * dbus/dbus-sysdeps.c (write_credentials_byte): Define cmsg struct, output it. (_dbus_read_credentials_unix_socket): Use cmsg struct. Patch from Joe Markus Clarke for FreeBSD support. 2005-06-16 Colin Walters * tools/dbus-send.c (append_array): Use strtok. (append_dict): New function. (type_from_name): New function, extracted from main. (main): Handle sending dicts. * tools/dbus-print-message.c (print_iter): Print dict entries. 2005-06-16 Colin Walters * glib/dbus-gvalue.c (marshal_basic): Marshal NULL string values as the empty string (#2948). 2005-06-16 Colin Walters * dbus/Makefile.am: * mono/doc/Makefile.am: * test/glib/Makefile.am: Fix srcdir != builddir issues (Patch from Chris Wilson, #3477) 2005-06-16 Colin Walters * dbus/dbus-marshal-header.c (_dbus_header_load): Set header byte order from expected byte order (Patch from Chris Wilson, #3475). * dbus/dbus-marshal-byteswap.c (byteswap_body_helper): Increment pointer after swapping fixed array. Add assertion for array length. 2005-06-15 Colin Walters * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): Fix call to dbus_set_error. (Patch from Michael Banck, #3461) 2005-06-15 John (J5) Palmieri * NEWS: Update to 0.34 2005-06-15 David Zeuthen * configure.in (LT_CURRENT): Revert back to 1 as the library hasn't changed and we've certainly not committed to protocol stability yet. All this does is to break ABI. See commit note from hp@redhat.com 2005-05-05 for details. 2005-06-15 John (J5) Palmieri * dbus/dbus-connection.c (_dbus_connection_peer_filter): New method (_dbus_connection_run_builtin_filters): New method (dbus_connection_dispatch): Run the builtin filters which in turn runs the peer filter which handles Ping messages. * doc/TODO: - Ping isn't handled: This patch fixes it - Add a test case for the Ping message: added TODO item 2005-06-15 John (J5) Palmieri * dbus/dbus-message.c: (dbus_message_has_path): New method (dbus_message_has_interface): New method (dbus_message_has_member): New method * dbus/dbus/dbus-sysdeps.c (_dbus_check_dir_is_private_to_user): New method * dbus/dbus-keyring.c (_dbus_keyring_reload): Check to see that the keyring directory is private to the user * doc/TODO: - The convenience functions in dbus-bus.h should perhaps have the signatures that they would have if they were autogenerated stubs. e.g. the acquire service function. We should also evaluate which of these functions to include, in light of the fact that GLib/Qt native stubs will probably also exist.: Punted - add dbus_message_has_path(), maybe has_member/interface: fixed in this patch - in dbus-keyring.c, enforce that the keyring dir is not world readable/writable: Fixed in this patch 2005-06-15 John (J5) Palmieri * dbus/dbus-marshal-validate.h: Added a new validation error code DBUS_VALIDITY_UNKNOWN_OOM_ERROR = -4 for out of memory errors when validating signitures * dbus/dbus-marshal-header.c: use DBUS_VALIDITY_UNKNOWN_OOM_ERROR in places where we previously used DBUS_VALID and a FALSE return value to indicate OOM * dbus/dbus-marshal-validate.c (_dbus_validate_signature_with_reason): Use a stack to track the number of elements inside containers. The stack values are then used to validate that dict entries have only two elements within them. (validate_body_helper): check the reason for failure when validating varients * dbus/dbus-message.c (load_message): use DBUS_VALIDITY_UNKNOWN_OOM_ERROR in places where we previously used DBUS_VALID and a FALSE return value to indicate OOM * doc/TODO: remove "- validate dict entry number of fields" as this patch fixes it 2005-06-14 David Zeuthen * bus/bus.c (process_config_every_time): Drop existing conf-dir watches (if applicable) and add new watches * bus/main.c (signal_handler): Handle SIGIO if using D_NOTIFY (main): Setup SIGIO signal handler if using D_NOTIFY * bus/config-parser.h: Add prototype bus_config_parser_get_conf_dirs * bus/config-parser.c (struct BusConfigParser): Add conf_dirs list (merge_included): Also merge conf_dirs list (bus_config_parser_unref): Clear conf_dirs list (include_dir): Add directory to conf_dirs list (bus_config_parser_get_conf_dirs): New function * bus/dir-watch.[ch]: New files * bus/Makefile.am (BUS_SOURCES): Add dir-watch.[ch] * configure.in: Add checks for D_NOTIFY on Linux 2005-06-14 Colin Walters * glib/dbus-binding-tool-glib.c: * glib/dbus-gobject.c: * glib/dbus-gvalue.c: Fix indentation and brace style. 2005-06-14 Ross Burton . * glib/dbus-glib.h: Make DBusGMethodInvocation a private structure. Rearrange prototypes a bit. * glib/dbus-gproxy.c (dbus_g_proxy_invoke): Add documentation for first_arg_type. * glib/dbus-gobject.c: Move DBusGMethodInvocation here, add documentation. Move dbus_g_method_return and dbus_g_method_return_error into public API section. 2005-06-14 Colin Walters * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Add missing return statements, noticed by Ross Burton. 2005-06-13 Ross Burton . * glib/dbus-gobject.c: Handle errors on message demarshalling by sending error message back. * glib/dbus-gvalue.c: Initialize return variables. 2005-06-13 Colin Walters * glib/Makefile.am: Fix thinko in last patch. 2005-06-13 Colin Walters * glib/Makefile.am: Move dbus-gtype-specialized.c and dbus-gtype-specialized.h into a _HEADERS variable, install them. 2005-06-12 Colin Walters Async signals and various bugfixes and testing by Ross Burton . * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests. 2005-06-06 David Zeuthen * doc/TODO: Add item about need to remove deprecated functions. * dbus/dbus-connection.h: Add prototype for dbus_connection_disconnect * dbus/dbus-connection.c (dbus_connection_disconnect): New function to repair the ABI which was broken with the last commit. 2005-06-02 John (J5) Palmieri * dbus/dbus-connection.c, dbus/dbus-connection.h (dbus_connection_disconnect): renamed to dbus_connection_close for API symmetry with dbus_connection_open (_dbus_connection_open_internal): s/dbus_connection_disconnect/dbus_connection_close * dbus/dbus-bus.c (dbus_bus_get): s/dbus_connection_disconnect/dbus_connection_close * bus/connection.c (bus_connections_unref, bus_connections_setup_connection, bus_connections_expire_incomplete): s/dbus_connection_disconnect/dbus_connection_close * bus/dispatch.c (bus_dispatch, kill_client_connection, kill_client_connection_unchecked, check_hello_connection): s/dbus_connection_disconnect/dbus_connection_close * bus/bus.c (new_connection_callback): s/dbus_connection_disconnect/dbus_connection_close * tools/dbus-send.c (main): s/dbus_connection_disconnect/dbus_connection_close * test/glib/test-profile.c (no_bus_thread_func, with_bus_thread_func): s/dbus_connection_disconnect/dbus_connection_close * test/test-service.c (path_message_func, filter_func): s/dbus_connection_disconnect/dbus_connection_close * doc/TODO: remove connection_open/connection_disconnect lacks symmetry item that was just fixed 2005-05-25 Colin Walters * dbus/dbus-protocol.h: Move various bus service #defines such as DBUS_SERVICE_DBUS and DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT to dbus/dbus-shared.h. * dbus/dbus-shared.h: Various defines moved here. * dbus/dbus-marshal-header.c: Include dbus-shared.h. 2005-05-25 John (J5) Palmieri * python/__init__.py: Python bindings deserve a minor version update. Upped to (0, 40, 2) 2005-05-24 John (J5) Palmieri * python/decorators.py: add explicitly_pass_message decorator for passing in the dbus message as keyword for edge case signal handling * python/matchrules.py (SignalMatchRule.__repr__): fix output to conform with what dbus expects for match rules (SignalMatchRule.execute): add the dbus message as a keyword if the signal handler has requested it * python/examples/example/signal-recipient.py: added some more examples on how to hook up to signals 2005-05-23 John (J5) Palmieri * python/decorators.py: import dbus_bindings * python/matchrules.py (SignalMatchRule, SignalMatchTree, SignalMatchNode): new classes that implement wildcard signal callback matching using a tree lookup. Heavily modified from a patch sent by Celso Pinto (fd.o bug #3241) * _dbus.py (add_signal_receiver, remove_signal_receiver, _signal_func): use new match classes to handle signals. 2005-05-19 John (J5) Palmieri * python/dbus_bindings.pyx.in: s/TYPE_PATH/TYPE_OBJECT_PATH 2005-05-18 Havoc Pennington * configure.in: use GLIB_GNU_GETTEXT to get INTLLIBS and require gettext. Not really worth requiring yet perhaps, but any production quality 1.0 would require it so we should go ahead and get things set up. We do have a couple token calls to bindtextdomain in the code already. 2005-05-16 John (J5) Palmieri * glib/dbus-gmain.c (io_handler_dispatch): fix deadlock when using recursive g_main_loops * python/_dbus.py (class Bus): add the ProxyObjectClass alias for ProxyObject to make it easier for the Twisted networking framework to integrate dbus. * python/proxies.py (class ProxyObject): add the ProxyMethodClass alias for ProxyMethod to make it easier for the Twisted networking framework to integrate dbus. 2005-05-11 Ross Burton * glib/dbus-glib-tool.c: Add --prefix argument. * glib/dbus-binding-tool-glib.h: Add prefix argument. * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Add prefix argument. (generate_glue): Pass prefix argument down. (dbus_binding_tool_output_glib_server): Pass prefix to glib-genmarshal. 2005-05-11 Colin Walters * tools/dbus-send.c (append_array): New function. (append_arg): Broken out from main. (main): Add cheesy hack to send arrays and variants. (usage): Update. * tools/dbus-print-message.c (print_iter): Broken out from main. 2005-05-11 Colin Walters * dbus/dbus-signature.c (dbus_signature_iter_get_signature): New function, returns signature string for signature iter. * dbus/dbus-signature.h: Prototype it. * dbus/dbus-message.c (dbus_message_iter_get_signature): New function, returns signature string for message iter. (dbus_message_iter_get_array_len): New function, returns length of array. (dbus_message_iter_get_fixed_array): Fix assertion; this function should be used when the iter is pointing to the contents of an array * dbus/dbus-message.h: Prototypes. * dbus/dbus-marshal-recursive.c (_dbus_type_reader_get_array_length): New function; returns length of an array. * dbus/dbus-marshal-recursive.h: Prototype it. 2005-05-11 Colin Walters * dbus/dbus-sysdeps-util.c : Fix compilation error. 2005-05-08 Havoc Pennington * dbus/dbus-sysdeps-util.c (_dbus_become_daemon): write the daemon's pid, not the parent's pid, to the file descriptor. Reported by Taj Morton. 2005-05-05 Havoc Pennington * configure.in (LT_*): add notes on how the libtool versioning works to save thinking. Increment soname to indicate protocol breakage (though really the library interface hasn't changed I guess) * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): verify the GUID received from server matches what we were expecting, if we had an expectation * dbus/dbus-auth.c (send_ok): send GUID along with the OK command (_dbus_auth_get_guid_from_server): new function (send_begin): parse the OK args * doc/dbus-specification.xml: add GUID to the auth protocol 2005-05-05 John (J5) Palmieri * Fix my name in previous changelog ;) * python/proxies.py (ProxyObject.__getattr__): add further patch from Anthony Baxter to throw an AttributeError when python __special__ functions are called instead of marshling them over the bus (Bug#1685 comment 3). 2005-05-04 John (J5) Palmieri * python/Makefile.am: changed to use pyexecdir for the binding shared libraries (Bug#2494) * python/exceptions.py: bring exceptions over from the bindings so they can be used in applications (Bug#2036) Make all exceptions derive from DBusException * python/_dbus.py, python/proxies.py: implement __repr__ in a couple of classes so that print obj doesn't throw an exception (Bug #1685) 2005-05-03 Ross Burton * glib/dbus-gobject.c (dbus_g_connection_register_g_object): Return if we get an error during registration. Set up a weak reference on object to unregister if object is destroyed. (unregister_gobject): New function. 2005-05-01 John (J5) Palmieri * python/dbus_bindings.pyx.in: - added new type classes for hinting to the marashaler what type to send over the wire - added int16 and uint16 marshalers - Fixed a bug in the type constants that caused int32 to go out as uint16 over the wire * python/dbus.py: split up into different files and renamed _dbus.py * python/__init__.py, python/_util.py, python/decorators.py, python/exceptions.py, python/proxies.py, python/services.py, python/types.py: new files split off from dbus.py * python/Makefile.am: Add new files, remove dbus.py and install all python files to /dbus * python/examples/*: Added #!/usr/bin/env python to the top of every example. Patch provided by Tatavarty Kalyan 2005-04-25 John (J5) Palmieri * NEWS: Update to 0.33 2005-04-25 John (J5) Palmieri * python/dbus_bindings.pyx.in (send_with_reply_handlers): New send method for doing async calls (_pending_call_notification): New C function for handling pendning call callbacks (set_notify): New method for setting pending call notification * python/dbus.py: new version tuple "version" is set at (0, 40, 0) Async capabilities added to remote method calls (Sender): class removed (RemoteService): class removed (ObjectTree): class removed for now (RemoteObject): Renamed to ProxyObject (RemoteMethod): Renamed to ProxyMethod (method): Decorator added for decorating python methods as dbus methods (signal): Decorator added for decorating python methods as signal emitters (ObjectType): Metaclass added for generating introspection data and the method callback vtable (Interface): Wrapper class added to wrap objects in a dbus interface (Object): Uses ObjectType as its metaclass and exports Introspect of the org.freedesktop.DBus.Introspectable interface (ValidationException, UnknownMethodException): new exceptions * python/examples/*: Modified to fit with the new bindings 2005-04-23 Havoc Pennington * dbus/dbus-message.c (dbus_message_append_args): fix doc comment, reported by Tony Houghton * test/test-service.c (main): test dbus_connection_get_object_path_data() * dbus/dbus-object-tree.c (find_handler): be sure we always init the exact_match (_dbus_object_tree_get_user_data_unlocked): new function used by dbus_connection_get_object_path_data() (do_register): add assertion test for get_user_data_unlocked (object_tree_test_iteration): more tests * dbus/dbus-connection.c (dbus_connection_get_object_path_data): new function from Dan Reed to let you get the user data from dbus_connection_register_object_path() 2005-04-23 John (J5) Palmieri * dbus/dbus-marshal-recursive-util.c: Fixed buffer overflow in numerous places that did not account for the NULL terminator (signature_from_seed): changed the manual string copy loop to just use strcpy instead make check should now pass 2005-04-19 John (J5) Palmieri * dbus/dbus-marshal-header.c (_dbus_header_create): Fix assert so that it allows messages that are not signals to pass in NULL as the interface. 2005-04-18 David Zeuthen * glib/dbus-gmain.c (io_handler_destroy_source): (timeout_handler_destroy_source, connection_setup_free): Also unref the source to avoid memory leaks. 2005-04-13 David Zeuthen * bus/config-parser.c (bus_config_parser_new): Bump this to a more reasonable, yet still totally arbitrary, value :-). 2005-04-13 David Zeuthen * doc/TODO: Added an "important for 1.0" item about selinux allow/deny messages 2005-04-13 David Zeuthen * bus/selinux.c: Add c-file-style to top of file (log_audit_callback): Don't free the data here anymore (bus_selinux_check): Don't take spid and tpid since appending that to auxdata may OOM. (bus_selinux_allows_acquire_service): Handle OOM and signal back to the caller if we are OOM by taking an error object. (bus_selinux_allows_send): -do- * bus/selinux.h: Fix prototypes for bus_selinux_allows_acquire_service and bus_selinux_allows_send * bus/bus.c (bus_context_check_security_policy): Pass error and pass on OOM thrown by bus_selinux_allows_send() * bus/services.c (bus_registry_acquire_service): Pass error and pass on OOM thrown by bus_selinux_allows_acquire_service() 2005-04-13 Havoc Pennington * glib/dbus-gmain.c (message_queue_dispatch): only dispatch one message at a time to avoid monopolizing the main loop, bug #2953 from Benjamin Otte 2005-04-09 Havoc Pennington * dbus/dbus-string.c (copy): change a memcpy to memmove due to possible overlap, fix from Daniel Reed (fixup_alignment): fix signedness warnings (_dbus_string_append_unichar): ditto 2005-04-09 Havoc Pennington * dbus/dbus-message-util.c (_dbus_message_test): fix signedness warning * glib/dbus-glib-tool.c (main): fix warning * glib/dbus-binding-tool-glib.c (generate_glue): fix warning * dbus/dbus-connection.c (dbus_connection_read_write_dispatch): add a new function that can be used in simple applications that don't have a main loop and are willing to block 2005-04-05 David Zeuthen Fix https://bugs.freedesktop.org/show_bug.cgi?id=2889 * glib/dbus-gmain.c: (io_handler_destroy_source): Remove from list of IO handlers of the ConnectionSetup object (timeout_handler_destroy_source): -do- for timeout handlers (io_handler_source_finalized): Don't remove from list since we now do that in io_handler_destroy_source(). Renamed from io_handler_source_destroyed (timeout_handler_source_destroyed): -do- for timeout handlers (connection_setup_free): It is now safe to iterate over all IO and timeout handlers as the _destroy_source removes them from the list synchronously 2005-03-30 Havoc Pennington * configure.in: change check to gtk 2.4 * tools/dbus-viewer.c (name_combo_changed_callback): remove gtk_combo_box_get_active_text() usage to decrement GTK requirement to 2.4 2005-03-29 John (J5) Palmieri * News: Update 0.32 * HACKING: Fixed realease instructions. configure.in should be updated to the next release by the person who made the last release. 2005-03-29 John (J5) Palmieri * python/lvalue_cast_post_process.py - removed. Patch has been submitted to Pyrex maintainers that fixes gcc4.0 errors * python/Makefile.am: removed refrences to lvalue_cast_post_process.py 2005-03-24 Daniel Reed * tools/Makefile.am: Make print-introspect and dbus-bus-introspect.xml building conditional on HAVE_GLIB. 2005-03-22 John (J5) Palmieri * tools/Makefile.am: Patch by Colin Walters that fixes distcheck * dbus/dbus-userdb.c, dbus/dbus-userdb-util.c: Add patch we have had in Red Hat packages for a while but for some reason never got merged upstream (_dbus_is_a_number): New checks if a string can be converted to a number and does the conversion if it can (_dbus_user_database_lookup): Add check to see if the given username is a udi. This allows udi's to be used instead of usernames in the config file. (_dbus_user_database_lookup_group): Add check to see if the given groupname is a gdi. This allows gdi's to be used instead of groupnames in the config file. 2005-03-21 John (J5) Palmieri * python/lvalue_cast_post_process.py - added post processor to fix Pyrex code so that it compiles with gcc4.0 * python/Makefile.am: Added lvalue_cast_post_process.py to EXTRA_DIST run dbus_bindings.c through lvalue_cast_post_process.py and copy the results back to dbus_binding.c 2005-03-20 Colin Walters Patch suggested by Inguva Rajasekhar . * configure.in: Require GTK+ 2.6. 2005-03-20 Colin Walters * Makefile.am (SUBDIRS, DIST_SUBDIRS): Build tools before test. 2005-03-17 Tom Parker * dbus/dbus-userdb.c (_dbus_user_database_lookup): Don't print DBUS_UID_UNSET; instead print passed username. Also be sure to actually use gid looked up in cache. * dbus/dbus-userdb-util.c (_dbus_user_database_lookup_group): Ditto for DBUS_GID_UNSET and groupname. 2005-03-17 Colin Walters * bus/print-introspect.c: Move to tools/. * bus/run-with-tmp-session-bus.sh: Ditto. * glib/Makefile.am (dbus-glib-bindings.h): Move generation to tools/Makefile.am. * test/glib/run-test.sh: Update to handle move of run-with-tmp-session-bus.sh. * test/glib/test-service-glib.c: Update to handle move of dbus-glib-bindings.h. * tools/print-introspect.c: Moved here from bus/, and ported to GLib bindings. * tools/run-with-tmp-session-bus.sh: Moved here from bus/. * tools/Makefile.am: Generate dbus-glib-bindings.h and dbus-bus-introspect.xml here. * tools/.cvsignore, glib/.cvsignore, bus/.cvsignore: Update. 2005-03-17 Colin Walters * bus/driver.c (write_args_for_direction): Use _dbus_string_get_const_data to retrieve string; _dbus_string_get_const_data_len doesn't actually return a NULL-terminated substring. * test/glib/test-service-glib.c: Include dbus-glib-bindings.h. (main): Change to use org_freedesktop_DBus_request_name instead of using g_proxy_begin_call/end_call. 2005-03-15 Joe Shaw * mono/ProxyBuilder.cs (BuildFinalizer): Fix some invalid IL when generating the finalizer. Fixes from Ben Maurer. 2005-03-12 Joe Shaw * mono/BusDriver.cs: Update method names: ListServices becomes ListNames; GetOwner becomes GetNameOwner. * mono/ProxyBuilder.cs (BuildFinalizer): Need to load arg 0 onto the eval stack when removing the delegate. 2005-03-12 Joe Shaw * mono/dbus-sharp.dll.config.in: Don't hardcode 0 for LT_CURRENT. Set it to the autoconf variable. * mono/ProxyBuilder.cs: Add a finalizer to the generated proxy classes that disconnects the signal handler delegate from the service object. Fixes a big leak of proxy objects on the client side of things. Patch from Ben Maurer 2005-03-12 Colin Walters * bus/driver.c (write_args_for_direction): New function, parses a type signature into arguments and outputs to XML. (bus_driver_handle_introspect): Use it instead of hardcoding XML for certain signatures. * bus/Makefile.am (dbus-bus-introspect.xml): Add dependency on dbus-daemon. * glib/dbus-glib-tool.c (main): Parse ignore_unsupported argument, pass it to dbus_binding_tool_output_glib_client. * glib/dbus-binding-tool-glib.c (generate_client_glue): Protect against multiple inclusion. (dbus_binding_tool_output_glib_client): Add G_BEGIN_DECLS/G_END_DECLS. * glib/dbus-binding-tool-glib.c (compute_client_method_name): Change to just take iface prefix directly. (write_formal_parameters): Clarify error message. (check_supported_parameters): New function; checks to see type signatures of method parameters are supported. (generate_client_glue): Handle ignore_unsupported flag. (dbus_binding_tool_output_glib_client): Handle ignore_unsupported parameter. * glib/Makefile.am (dbus-glib-bindings.h): Pass --ignore-unsupported by default until glib bindings support arrays. 2005-03-11 Colin Walters * glib/Makefile.am: Generate dbus-glib-bindings.h and install it. * bus/print-introspect.c: New file; prints introspection data for a given name and object path. * bus/run-with-tmp-session-bus.sh: New file, refactored from test/glib/run-test.sh. Creates a temporary session bus and runs another program. * test/glib/run-test.sh: Refactor to invoke run-with-tmp-session-bus.sh. * bus/driver.c (bus_driver_handle_introspect): Fix to print new introspection format. Also change to use DBUS_TYPE_x_AS_STRING macros instead of hardcoding. * glib/.cvsignore, bus/.cvsignore, test/glib/.cvsignore: Update. 2005-03-11 Joe Shaw * dbus/dbus-connection.c (dbus_connection_send_with_reply): Remove this unref; it doesn't match up evenly in some codepaths. (_dbus_connection_block_pending_call): Unref at every exitpoint; this evenly matches with the ref near the top of this function. 2005-03-09 Joe Shaw * dbus/dbus-object-tree.c (_dbus_object_tree_unregister_and_unlock): If checks are enabled and we try to unregister a path that's not registered, still go through the process of unlocking and don't just return. 2005-03-09 Colin Walters * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls to this are generated for client-side wrappers. Invokes a D-BUS method and returns reply values. * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New function; writes signature string for argument direction. (write_args_for_direction): Change to pass input values directly instead of via address, and fix indentation. (generate_client_glue): Change to invoke dbus_g_proxy_invoke. Also make generated wrappers inlineable. * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add note about using dbus_type_is_fixed. * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to dbus/dbus-signature.c as dbus_type_is_fixed. All callers updated. * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed. * dbus/dbus-signature.h: Prototype. * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix error printf code. * test/glib/test-dbus-glib.c (main): Be sure to clear error as appropriate instead of just freeing it. (main): Free returned strings using g_free. * test/glib/Makefile.am (test-service-glib-glue.h) (test-service-glib-bindings.h): Add dependency on dbus-binding-tool. * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT; simply maps a simple D-BUS type to GType. (dbus_dbus_type_to_gtype): Function which maps D-BUS type to GType. (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and initialize the value with it. (dbus_gvalue_binding_type_from_type): Unused, delete. (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for various types instead of unmarshalling to value data directly. Remove can_convert boolean. (dbus_gvalue_marshal): Remove duplicate initialization; switch to returning directly instead of using can_convert boolean. (dbus_gvalue_store): New function; not related to D-BUS per-se. Stores a GValue in a pointer to a value of its corresponding C type. * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type, add dbus_gvalue_store. 2005-03-08 Joe Shaw Fix a bunch of lifecycle and memory management problems in the mono bindings. * mono/Arguments.cs (Arguments): Implement IDisposable * mono/Bus.cs (Bus): Don't allow public instantiation. This is strictly a static class. * mono/Connection.cs: Move the DBusObjectPathVTable and associated delegates into this file. (Connection): Implement IDisposable. (Dispose): Disconnect the connection and set the raw connection pointer to IntPtr.Zero. (~Connection): Call Dispose(). (RegisterObjectPath): Added. Manages the registration of object paths so we can cleanly disconnect them at dispose/finalize time. (UnregisterObjectPath): Ditto. (set_RawConnection): Unregister all of the object paths when changing the underlying DBusConnection. Add them back onto the new connection, if any. * mono/Handler.cs: Don't implement IDisposable; it doesn't use any more unmanaged resources anymore, so it's not necessary. Move all the DBusObjectPathVTable stuff out of here. (Handler): Save references to our delegates so that they don't get finalized. Call Connection.RegisterObjectPath() instead of dbus_connection_register_object_path() directly. (Message_Called): Dispose the message after we're finished with it. * mono/Message.cs (Message): Implement IDisposable. (Dispose): Dispose the Arguments, and set the RawMessage to IntPtr.Zero. (SendWithReplyAndBlock): We own the ref to the reply that comes back from dbus_connection_send_with_reply_and_block() so add a comment about that and unref it after we've constructed a managed MethodReturn class around it. Fixes a big, big leak. * mono/ProxyBuilder.cs: Reflect into Message to get the Dispose method. (BuildSignalHandler): After we've sent the Signal message, dispose of it. (BuildMethod): Dispose of the method call and reply messages after we've sent the message and extracted the data we want from the reply. * mono/Service.cs (UnregisterObject): Don't call handler.Dispose() anymore. (Service_FilterCalled): Dispose of the message after we're finished with it. 2005-03-08 Joe Shaw * dbus/dbus-connection.c (dbus_connection_send_with_reply): After we attach our pending call to the connection, unref it. Fixes a leak. * mono/Connection.cs (set_RawConnection): Disconnect our filter and match callbacks from the old connection and reconnect them to the new connection, if any. * mono/DBusType/Array.cs: "Code" is a static member, so don't use "this" to refer to it. Fix for stricter checking in Mono 1.1.4. * mono/DBusType/ObjectPath.cs (Append): Don't leak the object path that we pass into unmanaged code. * mono/DBusType/String.cs (Append): Don't leak the string that we pass into unmanged code. 2005-03-07 John (J5) Palmieri * NEWS: Update for 0.31 * configure.in: Release 0.31 add LT_CURRENT, LT_REVISION, LT_AGE for easy soname bumping * qt/Makefile.am: fixed build * dbus/Makefile.am: soname bump for libdbus * glib/Makefile.am: soname bump for libdbus-glib 2005-03-05 Havoc Pennington * dbus/dbus-sysdeps.c: (pseudorandom_generate_random_bytes_buffer): fix to have no return value (_dbus_generate_random_bytes_buffer): fix return value * dbus/dbus-sysdeps-util.c: s/GETPWNAME/GETPWNAM/ so configure checks actually work, from Tom Parker 2005-03-01 Colin Walters * test/glib/test-dbus-glib.c (lose, lose_gerror): Utility functions copied from dbus-glib-tool.c. (main): Convert lots of error code to use them. Also add some testing for introspection bits. 2005-03-01 Colin Walters * doc/TODO: Remove introspection signature TODO. 2005-02-27 Colin Walters * glib/dbus-gidl.c (property_info_get_type, arg_info_get_type): Change return value to const char * instead of int so we can do full signatures. (struct PropertyInfo, struct ArgInfo): Store char *. (property_info_new, arg_info_new): Update parameters, strdup. (property_info_unref, arg_info_unref): Free. * glib/dbus-gidl.h: Update prototypes. * glib/dbus-gparser.c (basic_type_from_string): Delete. (validate_signature): New function, just validates signature and sets GError. (parse_property, parse_arg): Invoke validate_signature. Store signature instead of just type code. * glib/dbus-gvalue.c (base_type_from_signature): New utility function to return a primary type for a signature, dropping information about types in container types. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_binding_type_from_type) (dbus_gvalue_ctype_from_type): Update to take full signature instead of type code. (dbus_gtype_to_dbus_type): Moved here from glib/dbus-gobject.c. * glib/dbus-gvalue.h: Update prototypes for above. * glib/dbus-gobject.c (gtype_to_dbus_type): Moved to glib/dbus-gvalue.c as dbus_gtype_to_dbus_type. (introspect_properties, introspect_signals, write_interface): Update to handle signatures, and remove usage of _dbus_gutils_type_to_string. (handle_introspect): Print out type codes instead of e.g. "string" in hardcoded introspection XML; also use x_AS_STRING constants instead of hardcoding in string. * glib/dbus-glib-tool.c (pretty_print): Handle signature change to string. Remove usage of _dbus_gutils_type_to_string. * glib/dbus-gutils.c (_dbus_gutils_type_to_string): Delete. * glib/dbus-gutils.h (_dbus_gutils_type_to_string): Update for deletion. * glib/dbus-binding-tool-glib.c (compute_marshaller) (compute_marshaller_name, generate_glue): Handle signature change to string. (write_formal_parameters, write_args_for_direction): Ditto, and remove FIXME. * tools/dbus-tree-view.c (type_to_string): Delete. (info_set_func_text): Update to print full signatures. * test/glib/test-service-glib.xml: Change types to new introspection format. 2005-02-26 Havoc Pennington * doc/TODO: remove the "guid" item * test/glib/test-profile.c (no_bus_thread_func): use open_private (with_bus_thread_func): use open_private * dbus/dbus-connection.c (dbus_connection_open_private): new function that works like the old dbus_connection_open() (dbus_connection_open): now returns an existing connection if possible * dbus/dbus-server-unix.c (handle_new_client_fd_and_unlock): pass through the GUID to the transport * dbus/dbus-server.c (_dbus_server_init_base): keep around the GUID in hex-encoded form. * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): pass GUID argument in to the transport * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): add guid argument * dbus/dbus-transport.c (_dbus_transport_init_base): add guid argument * dbus/dbus-auth.c (_dbus_auth_server_new): add guid argument 2005-02-25 Havoc Pennington * doc/dbus-specification.xml: document the GUID thing * dbus/dbus-server.c (_dbus_server_init_base): initialize a globally unique ID for the server, and put a "guid=hexencoded" field in the address * dbus/dbus-bus.c: fix missing #include of dbus-threads-internal.h * dbus/dbus-message.c: ditto * dbus/dbus-dataslot.c: ditto * dbus/dbus-list.c: ditto * dbus/dbus-internals.h: wait, just include dbus-threads-internal.h here * dbus/dbus-string.c (_dbus_string_copy_to_buffer): move back for use in main library * dbus/dbus-sysdeps.c (_dbus_generate_random_bytes_buffer): new function 2005-02-24 Colin Walters * test/glib/Makefile.am (EXTRA_DIST): Add test-service-glib.xml 2005-02-24 John (J5) Palmieir * glib/Makefile.am: added dbus-gobject.h to sources list so distcheck doesn't fail 2005-02-24 Havoc Pennington * dbus/dbus-server.c, dbus/dbus-server-unix.c: change semantics so you must disconnect before unref, since locking and other things are screwed up otherwise. Fix assorted other locking stuff. * dbus/dbus-signature.c (dbus_signature_iter_get_element_type): fix compilation * dbus/dbus-threads-internal.h: move the mutex/condvar wrappers into a private header and don't export from the library * throughout - call _dbus_thread_stuff vs. dbus_thread_stuff 2005-02-24 Colin Walters * dbus/dbus-signature.c: New file; implements various functions related to type signatures. Includes an interator for parsing, validation functions. (dbus_type_is_basic): Moved here from dbus-marshal-basic.c:_dbus_type_is_basic. (dbus_type_is_container): Moved here from dbus-marshal-basic.c:_dbus_type_is_container. All callers of _dbus_type_is_container and _dbus_type_is_basic updated, and include dbus-signature.h. * dbus/dbus-signature.h: New file; prototypes for the above. * dbus/Makefile.am (DBUS_LIB_SOURCES): Add dbus-signature.c, dbus-signature.h. * dbus/dbus-marshal-basic.c (map_type_char_to_type): New utility function factored out of _dbus_first_type_in_signature. (_dbus_first_type_in_signature_c_str): New function; returns first type code for a type signature character. * dbus/dbus-marshal-basic.h: Prototype _dbus_first_type_in_signature_c_str, handle function moves. * dbus/dbus-marshal-recursive.h: Export _dbus_type_signature_next. * dbus/dbus-marshal-recursive.c (_dbus_type_signature_next): New function; skips to next complete type in type signature. Implemented using previous skip_one_complete_type. Now skip_one_complete_type just delegates to _dbus_type_signature_next. * dbus/dbus-marshal-basic.c (_dbus_type_is_basic): Moved to dbus-signature.c (_dbus_type_is_container): Ditto. * doc/dbus-specification.xml: Update introspection sample to use real type signatures. * dbus/dbus-test.h: Prototype signature test. * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): Run signature tests. * dbus/dbus-protocol.h (DBUS_ERROR_INVALID_SIGNATURE): New error. 2005-02-23 John (J5) Palmieri * python/dbus_bindings.pyx.in (PendingCall::get_reply): s/dbus_pending_call_get_reply/dbus_pending_call_steal_reply 2005-02-21 Colin Walters * dbus/dbus-test-main.c (main): Take optional specific test argument. * dbus/dbus-test.c (run_test): New function, runs a test function with no data directory. (run_data_test): Like above, but takes data directory. (dbus_internal_do_not_use_run_tests): Take specific test argument. Replace lots of cut n' paste code with run_test and run_data_test. * dbus/dbus-test.h: Update prototype for dbus_internal_do_not_use_run_tests. 2005-02-20 Havoc Pennington Fix bugs reported by Daniel P. Berrange * dbus/dbus-server.c (_dbus_server_unref_unlocked): new function (protected_change_watch): new function (_dbus_server_toggle_watch, _dbus_server_remove_watch) (_dbus_server_add_watch): change to work like the dbus-connection.c equivalents; like those, probably kind of busted, but should at least mostly work for now (dbus_server_disconnect): drop the lock if we were already disconnected, patch from Daniel P. Berrange * dbus/dbus-server.c (_dbus_server_toggle_timeout) (_dbus_server_remove_timeout, _dbus_server_add_timeout): all the same stuff * doc/TODO: todo about unscrewing this mess 2005-02-19 Colin Walters * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Fix iochannel refcounting. * glib/dbus-glib-tool.c: Include dbus-glib-tool.h, as well as errno.h and sys/stat.h. (lose): New function, prints error with newline and exits. (lose_gerror): Similar, but takes GError for message. (main): Add --output argument to specify output file to write to, instead of always printing to stdout. In this mode, determine timestamps on source files to see whether any are newer than the target file. If not, exit. Also convert a number of error messages to use lose (since it's shorter), and switch to using g_io_channel_shutdown. 2005-02-19 Havoc Pennington * glib/dbus-gobject.c (_dbus_glib_marshal_dbus_message_to_gvalue_array): add docs * glib/dbus-glib.c: fix doxygen warnings * glib/dbus-gparser.c (parse_annotation): error if an annotation is found on an 2005-02-17 Colin Walters * glib/dbus-gobject.h: Don't export _dbus_glib_marshal_dbus_message_to_gvalue_array. * glib/dbus-gobject.c (_dbus_glib_marshal_dbus_message_to_gvalue_array): Do rename. (invoke_object_method): Handle it. * glib/dbus-gproxy.c (marshal_dbus_message_to_g_marshaller): Handle rename. 2005-02-17 Colin Walters * bus/.cvsignore, doc/.cvsignore * test/data/valid-service-files/.cvsignore, test/glib/.cvsignore: Update. 2005-02-17 Colin Walters * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS): Rename to DBUS_SERVICE_DBUS. (DBUS_PATH_ORG_FREEDESKTOP_DBUS): Rename to DBUS_PATH_DBUS. (DBUS_PATH_ORG_FREEDESKTOP_LOCAL): Rename to DBUS_PATH_LOCAL. Change the value from "org.freedesktop.Local" to "org.freedesktop.DBus.Local". (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS): Rename to DBUS_INTERFACE_DBUS. (DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE): Rename to DBUS_INTERFACE_INTROSPECTABLE. Change the value from "org.freedesktop.Introspectable" to "org.freedesktop.DBus.Introspectable". (DBUS_INTERFACE_ORG_FREEDESKTOP_PROPERTIES): Rename to DBUS_INTERFACE_PROPERTIES. Change the value from "org.freedesktop.Properties" to "org.freedesktop.DBus.Properties". (DBUS_INTERFACE_ORG_FREEDESKTOP_PEER): Rename to DBUS_INTERFACE_PEER. Change the value from "org.freedesktop.Peer" to "org.freedesktop.DBus.Peer". (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL): DBUS_INTERFACE_LOCAL. Change the value from "org.freedesktop.Local" to "org.freedesktop.DBus.Local". All other users of those constants have been changed. * bus/driver.c (bus_driver_handle_introspect): Use constants. * glib/dbus-gobject.c (handle_introspect): Use constants. * doc/dbus-faq.xml, doc/dbus-specification.xml: Update for rename. 2005-02-17 Colin Walters * glib/dbus-gparser.c (struct Parser): Add in_annotation boolean. (parse_node, parse_interface, parse_method, parse_signal) (parse_property, parse_annotation): Lose if we're currently in an annotation. (parse_annotation): New function. (parser_start_element, parser_end_element): Handle annotation. (parse_method, parse_interface): Remove support for c_name attribute, switch to annotations. * glib/dbus-gidl.h (interface_info_get_binding_names) (method_info_get_binding_names) (interface_info_get_binding_name, method_info_get_binding_name) (interface_info_set_binding_name, method_info_set_binding_name): Remove. (interface_info_get_annotations, method_info_get_annotations) (interface_info_get_annotation, method_info_get_annotation) (interface_info_add_annotation, method_info_add_annotation): Prototype. * glib/dbus-gidl.c (struct InterfaceInfo): Substitute "annotations" for "bindings". (struct MethodInfo): Ditto. Straightfoward conversion of binding methods into annotation methods as prototyped. * glib/dbus-glib-tool.c (pretty_print): Print annotations. * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_C_SYMBOL): Define. * glib/dbus-binding-tool-glib.c (gather_marshallers, generate_glue): Use new annotation API. * doc/introspect.dtd: Fix a number of DTD syntax errors. Add annotation element. * doc/dbus-specification.xml: Discuss introspection annotations, include list of well-known annotations. * test/glib/test-service-glib.xml: Make validate against new DTD. 2005-02-17 Colin Walters This patch is based on initial work from Paul Kuliniewicz . * glib/dbus-gvalue.c (dbus_gvalue_init): New function; move initialization of GValue from dbus type to here. (dbus_gvalue_genmarshal_name_from_type): New function; generates a string for the "glib-genmarshal" program from a DBus type. (dbus_gvalue_binding_type_from_type): New function; turns a DBus type into the C name for it we use in the glib bindings. (dbus_gvalue_ctype_from_type): New function; maps a DBus type into a glib C type (not GValue). (dbus_gvalue_demarshal): invoke dbus_gvalue_init. * glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here from dbus-gobject.c. * glib/dbus-gutils.h: Prototype it. * glib/dbus-gproxy.c: Include new dbus-gobject.h. (marshal_dbus_message_to_g_marshaller): Use new shared function dbus_glib_marshal_dbus_message_to_gvalue_array. * glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute. Will be changed once we have annotations. * glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to GStaticRWLock. Callers updated. (wincaps_to_uscore): Move to dbus-gutils.c. Callers updated. (string_table_next): New function for iterating over zero-terminated string value array. (string_table_lookup): New function; retrieves specific entry in array. (get_method_data): New function; look up method data in object data chunk. (object_error_domain_prefix_from_object_info) (object_error_code_from_object_info): New functions, but not implemented yet. (method_interface_from_object_info): New function; retrieve interface name. (method_name_from_object_info): New function; retrieve method name. (method_arg_info_from_object_info): New function; retrieve argument data. (arg_iterate): New function; iterates over serialized argument data. (method_dir_signature_from_object_info): New function; returns a GString holding type signature for arguments for just one direction (input or output). (method_input_signature_from_object_info) (method_output_signature_from_object_info): New functions. (dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function; converts dbus message arguments into a GValue array. Used for both signal handling and method invocation. (struct DBusGlibWriteIterfaceData): New utility structure. (write_interface): New function; generate introspection XML for an interface. (introspect_interfaces): New function; gathers all interface->methods, generates introspection XML for them. (handle_introspect): Invoke introspect_interfaces. (get_object_property): Be sure to zero-initalize stack-allocated GValue. (lookup_object_and_method): New function; examines an incoming message and attempts to match it up (via interface, method name, and argument signature) with a known object and method. (gerror_domaincode_to_dbus_error_name): New function; converts a GError domain and code into a DBus error name. Needs GError data added to object introspection to work well. (gerror_to_dbus_error_message): Creates a DBusMessage error return from GError. (invoke_object_method): New function to invoke an object method looked up via lookup_object_and_method. Parses the incoming message, turns it into a GValue array, then invokes the marshaller specified in the DBusGMethodInfo. Creates a new message with either return values or error message as appropriate. (gobject_message_function): Invoke lookup_object_and_method and invoke_object_method. * glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h. (enum DBusBindingOutputMode): New enum for binding output modes. (pretty_print): Print binding names. (dbus_binding_tool_error_quark): GError bits. (version): Fix typo. (main): Create GIOChannel for output. Parse new --mode argument, possible values are "pretty-print", "glib-server", "glib-client". Use mode to invoke appropriate function. * glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array. * glib/dbus-glib-tool.h: New header, just includes GError bits for now. * glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable; maps binding style to name. (struct MethodInfo): Ditto. (get_hash_keys, get_hash_key): Utility function, returns keys for a GHashTable. (interface_info_new, method_info_new): Initialize bindings. (interface_info_unref, method_info_unref): Destroy bindings. (method_info_get_binding_names, method_info_get_binding_name) (interface_info_get_binding_names, interface_info_get_binding_name): Functions for retrieving binding names. (method_info_set_binding_name, interface_info_set_binding_name): Functions for setting binding names. * glib/dbus-binding-tool-glib.h: New file, has prototypes for glib binding generation. * glib/dbus-binding-tool-glib.c: New file, implements server-side and client-side glib glue generation. * glib/Makefile.am (dbus_binding_tool_SOURCES): Add dbus-binding-tool-glib.c, dbus-binding-tool-glib.h, dbus-glib-tool.h. * dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor of using GClosureMarshal directly. (struct DBusGObjectInfo): Add n_infos member. * test/glib/test-service-glib.xml: New file; contains introspection data for MyTestObject used in test-service-glib.c. * test/glib/test-service-glib.c (enum MyObjectError): New GError enum. (my_object_do_nothing, my_object_increment, my_object_throw_error) (my_object_uppercase, my_object_many_args): New test methods. (main): Use dbus_g_object_class_install_info to include generated object info. * test/glib/Makefile.am: Generate server-side glue for test-service-glib.c, as well as client-side bindings. * test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h. (main): Activate TestSuiteGLibService; test invoke a bunch of its methods using both the dbus_gproxy stuff directly as well as the generated bindings. 2005-02-15 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_dispatch): always complete a pending call, don't run filters first. * glib/dbus-gproxy.c (dbus_g_proxy_end_call): change to use dbus_pending_call_steal_reply * dbus/dbus-pending-call.c (dbus_pending_call_block): just call _dbus_connection_block_pending_call (dbus_pending_call_get_reply): change to steal_reply and return a ref * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): port to work in terms of DBusPendingCall (_dbus_connection_block_pending_call): replace block_for_reply with this 2005-02-14 Havoc Pennington * dbus/dbus-userdb-util.c (_dbus_user_database_lookup_group): properly handle looking up group information by name; fix from j@bootlab.org 2005-02-13 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_return_message) (dbus_connection_borrow_message): hold dispatch lock while message is outstanding (_dbus_connection_block_for_reply): hold dispatch lock while we block for the reply, so nobody steals our reply (dbus_connection_pop_message): hold the dispatch lock while we pluck the message 2005-02-13 Havoc Pennington * dbus/dbus-connection.c (_dbus_connection_acquire_dispatch) (_dbus_connection_release_dispatch) (_dbus_connection_acquire_io_path) (_dbus_connection_release_io_path): make the mutex and condvar control access to the "acquired" flag. Drop the connection lock while waiting on the condvar. Hopefully these are baby steps in roughly the right direction. 2005-02-13 Havoc Pennington * dbus/dbus-connection.c: use separate mutexes for the condition variables; this is some kind of baseline for sanity, but the condition variables still aren't used correctly afaict 2005-02-13 Havoc Pennington * dbus/dbus-object-tree.c (handle_default_introspect_and_unlock): fix a double-unlock * dbus/dbus-connection.c (_dbus_connection_detach_pending_call_unlocked): add this Initial semi-correct pass through to fix thread locking; there are still some issues with the condition variable paths I'm pretty sure * dbus/dbus-server.c: add a mutex on DBusServer and appropriate lock/unlock calls * dbus/dbus-connection.c (_dbus_connection_do_iteration_unlocked): rename to add _unlocked (struct DBusConnection): move "dispatch_acquired" and "io_path_acquired" to use only one bit each. (CONNECTION_LOCK, CONNECTION_UNLOCK): add checks with !DBUS_DISABLE_CHECKS (dbus_connection_set_watch_functions): hacky fix to reentrancy (_dbus_connection_add_watch, _dbus_connection_remove_watch) (_dbus_connection_toggle_watch, _dbus_connection_add_timeout) (_dbus_connection_remove_timeout) (_dbus_connection_toggle_timeout): drop lock when calling out to user functions; done in a hacky/bad way. (_dbus_connection_send_and_unlock): add a missing unlock (_dbus_connection_block_for_reply): add a missing unlock * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): drop lock in a hacky probably unsafe way to call out to user function 2005-02-12 Havoc Pennington * tools/dbus-tree-view.c (info_set_func_text): display more details on args * bus/driver.c (bus_driver_handle_list_services): list the bus driver * glib/dbus-gparser.c (parse_arg): generate an arg name if none is supplied * glib/dbus-gidl.c (signal_info_get_n_args): new function (method_info_get_n_args): new function 2005-02-12 Havoc Pennington * bus/driver.c (bus_driver_handle_introspect): add introspection for bus driver 2005-02-12 Havoc Pennington * bus/driver.c: put the signature of each bus driver method in the table of handlers and check it on incoming calls; this isn't really useful, but going to add introspect support in a minute. 2005-02-11 Joe Shaw * mono/Connection.cs: The unpredictability of finalizers in mono prevents us from deterministically disconnecting the filters from the Service class's finalizer, so move tracking of filters and matches here. Add API for that. * mono/Service.cs: Remove the code, add code which calls the methods now on the Connection class. 2005-02-11 John (J5) Palmieri * python/dbus.py (class Sender): added to support dbus signals better (Bus::add_signal_receiver): added expand_args parameter which defaults to True. When expand args is True the signal handler will pass the message arguments as parameters to the signal handler. If False revert to previous behavior where the signal handler must get the argument list from the message. This is to help port applications like HAL that have a tendancy to send variable length argument lists. self._match_rule_to_receivers is now a dict of dicts. (Bus::remove_signal_receiver): pop handler off the dict intead of removing it from a list (Bus::_signal_func): change signal handlers so that interface, signal_name, service, path and message are packed into a Sender object and that is passed to the handler. If expand_args is True extract the args list from the message and append it to the parameter list * python/dbus_bindings.pyx.in (class Signature): added to support signiature types (MessageIter::__init__): changed iteration limit to match D-BUS (MessageIter::get*): added INT16, UINT16, SIGNATURE, DICT_ENTRY, STRUCT and VARIENT type support (MessageIter::python_value_to_dbus_sig): made recursive to support recursive types (MessageIter::append*): added Signature, dict, tuple support * python/examples/example-client.py: added examples of getting tuples and dicts * python/examples/example-service.py: added examples of sending tuples and dicts * python/examples/example-signal-recipient.py: Fixed to handle new signal callback format 2005-02-10 Havoc Pennington * test/glib/test-dbus-glib.c (main): fix so this test doesn't fail (call dbus_g_proxy_add_signal) * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): escape the hostname (_dbus_server_new_for_domain_socket): escape the path * dbus/dbus-address.c (dbus_address_escape_value): new (dbus_address_unescape_value): new (dbus_parse_address): unescape values * dbus/dbus-string.c (_dbus_string_append_byte_as_hex): new function * doc/dbus-specification.xml: explain how to escape values in addresses 2005-02-10 Havoc Pennington * dbus/dbus-message-factory.c (generate_special): modify test to avoid using a non-basic dict key * dbus/dbus-marshal-validate-util.c: add test for the below * doc/dbus-specification.xml: require that dict keys are a basic type * dbus/dbus-marshal-validate.c (_dbus_validate_signature_with_reason): require that dict key is a basic type 2005-02-10 Havoc Pennington * dbus/dbus-object-tree.c (handle_default_introspect_and_unlock): change to be _and_unlock instead of _unlocked * dbus/dbus-connection.c (_dbus_connection_send_preallocated_unlocked_no_update): rename to have no_update so we can find this bug quickly in future 2005-02-10 Havoc Pennington * dbus/dbus-message-util.c (verify_test_message): tests for string array * dbus/dbus-message.c (dbus_message_append_args_valist): add support for arrays of string/signature/path 2005-02-10 Joe Shaw * dbus/dbus-connection.c (_dbus_connection_queue_received_message_link, _dbus_connection_message_sent): Add the path to the verbose output. (_dbus_connection_send_preallocated_and_unlock): Added. Calls _dbus_connection_send_preallocated_unlocked(), updated the dispatch status, and unlocks. Fixes a bug where certain situations (like a broken pipe) could cause a Disconnect message to not be sent, tricking the bus into thinking a service was still there when the process had quit. (_dbus_connection_send_preallocated): Call _dbus_connection_send_preallocated_and_unlock(). (_dbus_connection_send_and_unlock): Added. Calls _dbus_connection_send_preallocated_and_unlock(). (dbus_connection_send): Call _dbus_connection_send_and_unlock(). (dbus_connection_send_with_reply): Update the dispatch status and unlock. * mono/Service.cs (~Service): Added. Removes the filter so that we don't get unmanaged code calling back into a GCed delegate. (RemoveFilter); Added. 2005-02-09 John (J5) Palmieri * dbus/dbus-message.c (dbus_message_iter_open_container): - Removed check for iterator type being an array because get_arg_type does not work with writer iterators - Pass NULL to _dbus_type_writer_recurse if signiture is NULL 2005-02-07 Havoc Pennington * doc/dbus-specification.xml: some more language cleanups; add stuff about how to deal with invalid protocol and extension points; add _ to allowed chars in auth commands; add EXTENSION_ auth command prefix 2005-02-06 Havoc Pennington * s/expected/required/ in a couple places for clarity 2005-02-07 Colin Walters * bus/selinux.c (bus_selinux_allows_send): Handle NULL for sender or proposed_recipient. 2005-02-06 Havoc Pennington * dbus/dbus-message-factory.c (generate_special): more tests * dbus/dbus-marshal-validate.c (validate_body_helper): detect array length that exceeds the maximum 2005-02-05 Havoc Pennington * dbus/dbus-message-factory.c (generate_special): more test cases, increasing coverage * dbus/dbus-marshal-validate.c (validate_body_helper): return the reason why a signature was invalid * dbus/dbus-marshal-header.c (load_and_validate_field): fix to skip the length of the string before we look at it in validation * dbus/dbus-string-util.c (_dbus_string_test): add tests for equal_substring * dbus/dbus-message.c (_dbus_message_loader_new): default max_message_length to DBUS_MAXIMUM_MESSAGE_LENGTH 2005-02-05 Havoc Pennington * dbus/dbus-marshal-validate.c (validate_body_helper): fix crash if the signature of a variant was empty (_dbus_validate_signature_with_reason): catch "(a)" (array inside struct with no element type) * dbus/dbus-message-factory.c (generate_uint32_changed): add more mangled messages to break things 2005-02-04 Havoc Pennington * glib/dbus-gproxy.c (dbus_g_proxy_disconnect_signal): use g_quark_try_string() so it actually can return 0 (dbus_g_proxy_connect_signal): ditto 2005-02-04 Havoc Pennington * glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): fix a bogus warning (tristring_from_message): assert cleanly on null path/interface (should not be possible though I decided later) (dbus_g_proxy_dispose): move proxy manager unregistration here (DBUS_G_PROXY_DESTROYED): add this macro, and use it in a bunch of g_return_if_fail() checks 2005-02-04 Havoc Pennington * doc/Makefile.am (EXTRA_DIST): add DTDs to makefile * doc/introspect.dtd: add introspect.dtd from David A. Wheeler (with some minor changes) * doc/dbus-specification.xml: add deprecated attribute to introspection format 2005-01-31 Havoc Pennington * glib/dbus-gproxy.c: rewrite how signals work again, this time I think it's sort of right 2005-01-30 Havoc Pennington * tools/dbus-viewer.c: kind of half-ass hook up the option menu. 2005-01-30 Havoc Pennington * tools/dbus-names-model.c: dynamically watch NameOwnerChanged * autogen.sh: change to autotools 1.9 * glib/dbus-gproxy.c: completely change how signals work (dbus_g_proxy_add_signal): new function to specify signature of a signal (dbus_g_proxy_emit_received): marshal the dbus message to GValues, and g_warning if the incoming message has the wrong signature. 2005-01-30 Havoc Pennington * tools/dbus-names-model.c (have_names_notify): fix this * dbus/dbus-message.c (_dbus_message_iter_get_args_valist): clean up the string array handling a bit 2005-01-30 Havoc Pennington * glib/dbus-glib.c (dbus_g_pending_call_set_notify): new function (dbus_g_pending_call_cancel): new function * dbus/dbus-glib.h: move GType decls for connection/message here; * dbus/dbus-glib.c: move all the g_type and ref/unref stuff in here, just kind of rationalizing how we handle all that * tools/dbus-names-model.c: new file for a tree model listing the services on a bus * tools/dbus-tree-view.c (model_new): use proper typing on the model rows 2005-01-30 Havoc Pennington * glib/dbus-gmain.c: add a custom GSource back that just checks whether the message queue has anything in it; otherwise, there are cases where we won't see messages in the queue since there was no IO visible to the glib main loop * dbus/dbus-connection-internal.h (_DBUS_DEFAULT_TIMEOUT_VALUE): increase default message timeout to 25 seconds 2005-01-30 Havoc Pennington * test/glib/test-profile.c (no_bus_stop_server): remove the warning about the g_warning that I just fixed * glib/dbus-gmain.c: rewrite the main loop stuff to avoid the custom source, seems to be a lot easier to understand and work better. 2005-01-30 Havoc Pennington I think this main loop thing is conceptually broken, but here are some band aids. I'll maybe rewrite it in a minute. * glib/dbus-gmain.c (add_timeout): timeout stuff doesn't use the custom GSource, so don't pass it in; confusing (gsource_server_finalize, gsource_connection_finalize): add finalize handlers that remove all the watches. 2005-01-30 Havoc Pennington * glib/dbus-gobject.c (introspect_properties): fix the XML generated * dbus/dbus-message.c (dbus_message_unref): add an in_cache flag which effectively detects the use of freed messages * glib/dbus-gobject.c (handle_introspect): modify and return the reply message instead of the incoming message * dbus/dbus-object-tree.c (handle_default_introspect_unlocked): gee, maybe it should SEND THE XML instead of just making a string and freeing it again ;-) * tools/dbus-print-message.c (print_message): improve printing of messages * configure.in: add debug-glib.service to the output 2005-01-30 Havoc Pennington dbus-viewer introspected and displayed the bus driver * dbus/dbus-object-tree.c (object_tree_test_iteration): add tests for a handler registered on "/" * dbus/dbus-object-tree.c (_dbus_decompose_path): fix to handle path "/" properly (run_decompose_tests): add tests for path decomposition * glib/dbus-gutils.c (_dbus_gutils_split_path): fix to handle "/" properly * glib/dbus-gobject.c (handle_introspect): fix quotes * test/glib/run-test.sh: support launching the bus, then running dbus-viewer * test/glib/test-service-glib.c (main): put in a trivial gobject subclass and register it on the connection * bus/driver.c (bus_driver_handle_introspect): implement introspection of the bus driver service * dbus/dbus-protocol.h: add #defines for the XML namespace, identifiers, doctype decl * bus/driver.c (bus_driver_handle_get_service_owner): handle attempts to get owner of DBUS_SERVICE_ORG_FREEDESKTOP_DBUS by returning the service unchanged. (bus_driver_handle_message): remove old check for reply_serial in method calls, now the message type deals with that (bus_driver_handle_message): handle NULL interface * glib/dbus-gproxy.c (dbus_g_proxy_get_bus_name): new function * glib/dbus-gloader-expat.c (description_load_from_string): allow -1 for len * tools/dbus-viewer.c: add support for introspecting a service on a bus * glib/dbus-gproxy.c (dbus_g_pending_call_ref): add (dbus_g_pending_call_unref): add 2005-01-29 Havoc Pennington * tools/dbus-tree-view.c: add support for displaying properties. (run dbus-viewer with an introspect xml file as arg, then resize the window so the tree elements show up, not sure what that is) * glib/dbus-gobject.c (handle_introspect): return org.freedesktop.Properties and org.freedesktop.Introspectable interfaces when we are introspected. * doc/dbus-specification.xml: allow empty interface name when Get/Set a property 2005-01-29 Havoc Pennington * glib/Makefile.am: rename dbus-glib-tool to dbus-binding-tool; though it uses glib, it could be extended for any binding in principle * glib/dbus-gobject.c (gobject_message_function): change to the new way properties work * dbus/dbus-protocol.h: add the new interfaces * doc/dbus-specification.xml: document the introspection format, Introspectable interface, and add an org.freedesktop.Properties interface. * glib/dbus-gparser.c: add support for a element * glib/dbus-gidl.c: add PropertyInfo * glib/dbus-gobject.c (handle_introspect): put the outermost outside the signal and property descriptions. (introspect_properties): export properties as rather than as method calls 2005-01-28 Havoc Pennington * doc/TODO, doc/dbus-specification.xml: spec and TODO tweaks related to authentication protocol 2005-01-28 John (J5) Palmieri * python/dbus_bindings.pyx.in: Updated to handle new D-BUS type system - BUS_ACTIVATION -> BUS_STARTER - DBUS_BUS_ACTIVATION -> DBUS_BUS_STARTER - class MessageIter (__init__): Added recursion checking so we throw a nice error instead of just disconnecting from the bus. (get): Added arg_type parameter for recursion. Removed the nil type Added signiture type placeholder (not implemented) Added struct type placeholder (not implemented) Added varient type placeholder (not implemented) Commented out dict type for now (get_element_type): renamed from get_array_type (get_*): changed to use the dbus_message_iter_get_basic API (get_*_array): removed in favor of recursive get_array method (get_array): new recursive method which calls get to marshal the elements of the array (value_to_dbus_sig): New method returns the corrasponding dbus signiture to a python value (append): Comment out dict handling for now Handle lists with the new recursive API Comment out None handling for now (append_nil): removed (append_*): changed to use dbus_message_iter_append_basic API (append_*_array): removed in favor of recursive append_array method (__str__): Make it easier to print out recursive iterators for debugging - class Message (__str__): moved type inspection to the MessageIter class' __str__ method (get_iter): Added an append parameter wich defaults to False If True use the new API's to create an append iterator * python/dbus.py: Update to use new bindings API - TYPE_ACTIVATION -> TYPE_STARTER - class Bus (_get_match_rule): GetServiceOwner -> GetNameOwner - class ActivationBus -> class StarterBus - class RemoteObject (__call__): get an append iterator - (_dispatch_dbus_method_call): get an append iterator - class Object (emit_signal): get an append iterator * python/examples/: Fixed up the examples to work with the new API 2005-01-28 Joe Shaw * configure.in: Bump version up to 0.30. * HACKING: Add a release item to bump the version number up after a release. 2005-01-28 Havoc Pennington * doc/dbus-specification.xml: update to describe 16-bit types and dict entries * dbus/dbus-marshal-basic.c (_dbus_unpack_uint16): fix broken assertion * dbus/dbus-protocol.h (DBUS_TYPE_DICT_ENTRY): add DICT_ENTRY as a type * dbus/dbus-marshal-recursive.c: implement 2005-01-27 Havoc Pennington * dbus/dbus-arch-deps.h.in: add 16/32-bit types * configure.in: find the right type for 16 and 32 bit ints as well as 64 * dbus/dbus-protocol.h (DBUS_TYPE_INT16, DBUS_TYPE_UINT16): add the 16-bit types so people don't have to stuff them in 32-bit or byte arrays. 2005-01-27 Havoc Pennington * dbus/dbus-message.c: byteswap the message if you init an iterator to read/write from it * dbus/dbus-marshal-byteswap.c: new file implementing _dbus_marshal_byteswap() * dbus/dbus-marshal-basic.c: add _dbus_swap_array() 2005-01-26 Havoc Pennington * dbus/dbus-marshal-validate-util.c: break this out (and fix build, apparently - nobody noticed?) 2005-01-26 Havoc Pennington * dbus/dbus-marshal-recursive.h: remove todo comment 2005-01-25 Joe Shaw * Land the mono binding changes to conform to the new APIs. * mono/Makefile.am: Remove Custom.cs, DBusType/Custom.cs, DBusType/Dict.cs, and DBusType/Nil.cs from the build. * mono/Arguments.cs (GetCodeAsString): Added. Returns the dbus type code as a string. (InitAppending): Rename dbus_message_append_iter_init() to dbus_message_iter_init_append(). * mono/BusDriver.cs: Rename ServiceEventHandler to NameOwnerChangedHandler. Rename GetServiceOwner to GetOwner. Rename ServiceOwnerChanged to NameOwnerChanged. * mono/Connection.cs: Rename BaseService to UniqueName, and the underlying C call. * mono/Custom.cs: Removed. The CUSTOM type has been removed. * mono/Service.cs: Rename Exists to HasOwner, internally rename dbus_bus_acquire_service() to dbus_bus_request_name(). * mono/DBusType/Array.cs (ctor): Use Type.GetElementType() instead of Type.UnderlyingSystemType to get the correct element type for the array. (ctor): Update code for new APIs: use dbus_message_iter_recurse(), dbus_message_get_{element|arg}_type() instead of dbus_message_iter_init_array_iterator(). (Append): Replace dbus_message_iter_append_array() with dbus_message_iter_open_container() and dbus_message_iter_close_container(). * mono/DBusType/Custom.cs, mono/DBusType/Nil.cs: Removed. These types have been removed. * mono/DBusType/*.cs: Replace calls of dbus_message_iter_get_[type]() to dbus_message_iter_get_basic(), but specify the type in the DllImport extern declaration. Ditto for dbus_message_iter_append_[type]() -> dbus_message_iter_append_basic(). * mono/example/BusListener.cs: Update for ServiceEventHandler -> NameOwnerChangedHandler. 2005-01-25 John (J5) Palmieri * python/dbus_bindings.pyx.in: Rename of methods and bindings - get_base_service -> get_unique_name - bus_get_base_service -> bus_get_unique_name - dbus_bus_get_base_service -> dbus_bus_get_unique_name - ACTIVATION_REPLY_ACTIVATED -> DBUS_START_REPLY_SUCCESS - ACTIVATION_REPLY_ALREADY_ACTIVE -> DBUS_START_REPLY_ALREADY_RUNNING - bus_activate_service -> bus_start_service_by_name - dbus_bus_activate_service -> dbus_bus_start_service_by_name - bus_acquire_service -> bus_request_name - dbus_bus_acquire_service -> dbus_bus_request_name - bus_service_exists -> bus_name_has_owner - dbus_bus_service_exists -> dbus_bus_name_has_owner * python/dbus.py: Rename of methods - activate_service -> start_service_by_name - bus_acquire_service -> bus_request_name - ACTIVATION_REPLY_ACTIVATED -> START_REPLY_SUCCESS - ACTIVATION_REPLY_ALREADY_ACTIVE -> START_REPLY_ALREADY_RUNNING 2005-01-24 Joe Shaw * dbus/dbus-connection.c (dbus_connection_dispatch): Print out the signature for the method that can't be found. * dbus/dbus-message.c (dbus_message_iter_init): To check to see if the message has any arguments, we need to call _dbus_type_reader_get_current_type(), not _dbus_type_reader_has_next(). 2005-01-24 Havoc Pennington * dbus/dbus-message-factory.c: more testing of message validation * dbus/dbus-protocol.h (DBUS_MINIMUM_HEADER_SIZE): move to this header 2005-01-23 Havoc Pennington * dbus/dbus-message-factory.c, dbus/dbus-message-util.c: get this all working, not many tests in the framework yet though 2005-01-22 Havoc Pennington * doc/dbus-faq.xml, doc/dbus-tutorial: add a FAQ and update tutorial, based on work from David Wheeler. 2005-01-21 Havoc Pennington * dbus/dbus-bus.c: add more return_if_fail checks * dbus/dbus-message.c (load_message): have the "no validation" mode (have to edit the code to toggle the mode for now though) * dbus/dbus-marshal-header.c (_dbus_header_load): have a mode that skips all validation; I want to use this at least for benchmark baseline, I'm not sure if it should be a publicly-available switch. 2005-01-21 Havoc Pennington * glib/dbus-gmain.c: don't put the GLib bindings in the same toplevel doxygen group as the low-level API stuff * dbus/dbus.h: note that libdbus is the low-level API 2005-01-20 Havoc Pennington * update-dbus-docs.sh: script to update docs on the web site, only works for me though. neener. 2005-01-20 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_poll): amazingly, trying to compile code can reveal bugs in it 2005-01-20 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_poll): fix several bugs in the select() version, patches from Tor Lillqvist 2005-01-20 Havoc Pennington * doc/dbus-tutorial.xml: replace > with > * bus/services.c (bus_registry_acquire_service): validate the name and return a better error if it's no good. * doc/dbus-specification.xml: note NO_AUTO_START change * dbus/dbus-protocol.h (DBUS_HEADER_FLAG_NO_AUTO_START): change from AUTO_START, we're toggling the default * bus/dispatch.c: adapt the tests to change of auto-start default 2005-01-18 Havoc Pennington * rename dbus-daemon-1 to dbus-daemon throughout 2005-01-18 Havoc Pennington * Throughout, grand renaming to strip out the use of "service", just say "name" instead (or "bus name" when ambiguous). Did not change the internal code of the message bus itself, only the programmer-facing API and messages. * doc/dbus-specification.xml: further update the message bus section * bus/config-parser.c (all_are_equiv): fix bug using freed string in error case 2005-01-17 Havoc Pennington * dbus/dbus-types.h: remove 16-bit types since we don't use them ever * dbus/dbus-marshal-validate.c (_dbus_validate_path): disallow any "invalid name character" not only non-ASCII * doc/dbus-specification.xml: further update spec, message bus parts are still out-of-date but the marshaling etc. stuff is now accurate-ish 2005-01-17 Havoc Pennington * doc/dbus-specification.xml: partially update spec 2005-01-17 Havoc Pennington * Throughout, align variant bodies according to the contained type, rather than always to 8. Should save a fair bit of space in message headers. * dbus/dbus-marshal-validate.c (_dbus_validate_body_with_reason): fix handling of case where p == end * doc/TODO: remove the dbus_bool_t item and variant alignment items 2005-01-17 Havoc Pennington * dbus/dbus-types.h: hardcode dbus_bool_t to 32 bits * Throughout: modify DBUS_TYPE_BOOLEAN to be a 32-bit type instead of an 8-bit type. Now dbus_bool_t is the type to use whenever you are marshaling/unmarshaling a boolean. 2005-01-16 Havoc Pennington This is about it on what can be disabled/deleted from libdbus easily, back below 150K anyhow. Deeper cuts are more work than just turning the code off as I've done here. * dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the signed int convenience funcs * dbus/dbus-internals.c (_dbus_verbose_real): omit when not in verbose mode * dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking things out of libdbus * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same * dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it tests-enabled-only, though it should probably be deleted) * dbus/dbus-message-util.c: same stuff * dbus/dbus-auth-util.c: same stuff 2005-01-16 Havoc Pennington * dbus/dbus-userdb-util.c: split out part of dbus-userdb.c * dbus/dbus-sysdeps.c (_dbus_uid_from_string): move here to pave way for stripping down dbus-userdb.c stuff included in libdbus. Rename _dbus_parse_uid for consistency. 2005-01-16 Havoc Pennington * dbus/dbus-internals.c (_dbus_real_assert): print the function name the assertion failed in * dbus/dbus-internals.h (_dbus_return_if_fail) (_dbus_return_val_if_fail): assert that the name of the function containing the check doesn't start with '_', since we only want to use checks on public functions * dbus/dbus-connection.c (_dbus_connection_ref_unlocked): change checks to assertions * dbus/dbus-marshal-header.c (_dbus_header_set_field_basic): change checks to asserts for private function * dbus/dbus-message.c (_dbus_message_set_serial): checks to asserts for private function * dbus/dbus-marshal-recursive.c (skip_one_complete_type): remove broken assertion that was breaking make check (_dbus_type_reader_array_is_empty): remove this rather than fix it, was only used in assertions 2005-01-16 Havoc Pennington * test/unused-code-gc.py: hacky script to find code that's used only by the bus (not libdbus) or used only by tests or not used at all. It has some false alarms, but looks like we can clean up a lot of size from libdbus. * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-utils.c, dbus/Makefile.am: initially move 10K of binary size out of libdbus 2005-01-16 Havoc Pennington * Add and fix docs according to Doxygen warnings throughout source. * dbus/dbus-marshal-recursive.c (_dbus_type_reader_array_is_empty): change this to just call array_reader_get_array_len() and make it static * dbus/dbus-message.c (dbus_message_iter_get_element_type): rename from get_array_type (dbus_message_iter_init_append): rename from append_iter_init * dbus/dbus-marshal-recursive.c (_dbus_type_reader_get_element_type): rename from _dbus_type_reader_get_array_type 2005-01-15 Havoc Pennington * test/glib/test-profile.c (with_bus_server_filter): fix crash * dbus/dbus-marshal-basic.c (_dbus_unpack_uint32): inline as macro when DBUS_DISABLE_ASSERT (_dbus_marshal_set_basic): be sure we align for the string length * dbus/dbus-marshal-recursive.c (skip_one_complete_type): make this look faster * dbus/dbus-string.c (_dbus_string_get_const_data_len): add an inline macro version (_dbus_string_set_byte): provide inline macro version 2005-01-15 Havoc Pennington * Land the new message args API and type system. This patch is huge, but the public API change is not really large. The set of D-BUS types has changed somewhat, and the arg "getters" are more geared toward language bindings; they don't make a copy, etc. There are also some known issues. See these emails for details on this huge patch: http://lists.freedesktop.org/archives/dbus/2004-December/001836.html http://lists.freedesktop.org/archives/dbus/2005-January/001922.html * dbus/dbus-marshal-*: all the new stuff * dbus/dbus-message.c: basically rewritten * dbus/dbus-memory.c (check_guards): with "guards" enabled, init freed blocks to be all non-nul bytes so using freed memory is less likely to work right * dbus/dbus-internals.c (_dbus_test_oom_handling): add DBUS_FAIL_MALLOC=N environment variable, so you can do DBUS_FAIL_MALLOC=0 to skip the out-of-memory checking, or DBUS_FAIL_MALLOC=10 to make it really, really, really slow and thorough. * qt/message.cpp: port to the new message args API (operator<<): use str.utf8() rather than str.unicode() (pretty sure this is right from the Qt docs?) * glib/dbus-gvalue.c: port to the new message args API * bus/dispatch.c, bus/driver.c: port to the new message args API * dbus/dbus-string.c (_dbus_string_init_const_len): initialize the "locked" flag to TRUE and align_offset to 0; I guess we never looked at these anyhow, but seems cleaner. * dbus/dbus-string.h (_DBUS_STRING_ALLOCATION_PADDING): move allocation padding macro to this header; use it to implement (_DBUS_STRING_STATIC): ability to declare a static string. * dbus/dbus-message.c (_dbus_message_has_type_interface_member): change to return TRUE if the interface is not set. * dbus/dbus-string.[hc]: move the D-BUS specific validation stuff to dbus-marshal-validate.[hc] * dbus/dbus-marshal-basic.c (_dbus_type_to_string): move here from dbus-internals.c * dbus/Makefile.am: cut over from dbus-marshal.[hc] to dbus-marshal-*.[hc] * dbus/dbus-object-tree.c (_dbus_decompose_path): move this function here from dbus-marshal.c 2005-01-12 Joe Shaw * NEWS: Update for 0.23. * configure.in: Release 0.23. 2005-01-12 Joe Shaw * mono/Makefile.am, mono/example/Makefile.am: Always build the dbus DLL with --debug. Clean up after the .mdb files this leaves behind. * mono/doc/Makefile.am: Need to uninstall the docs on "make uninstall" * mono/Arguments.cs (GetDBusTypeConstructor): If the type is an enum, get the enum's underlying type. Another mono 1.1.3 fix. 2005-01-11 Joe Shaw Patch from Sjoerd Simons * mono/Makefile.am, mono/example/Makefile.am: Don't redefine DESTDIR. It breaks stuff. 2005-01-11 Joe Shaw Patch from Tambet Ingo * mono/DBusType/Array.cs (Get): Get the underlying element type by calling type.GetElementType(). The code previously depended on broken Mono behavior, which was fixed in Mono 1.1.3. * mono/DBusType/Dict.cs (constructor): Fix the parameters for Activator.CreateInstance() so that the class's constructor is called with the right parameters. 2005-01-11 Joe Shaw Patch from Timo Teräs * dbus/dbus-connection.c (_dbus_connection_queue_received_message_link): Call _dbus_connection_remove_timeout() instead of the _locked() variant, since it's always called from _dbus_connection_handle_watch(), which handles the locking. Removed the _locked() variant since it's no longer used. 2005-01-03 Havoc Pennington * dbus/dbus-internals.h: I'm an idiot, _dbus_assert certainly can return 2004-12-26 Havoc Pennington * dbus/dbus-internals.h: add _DBUS_GNUC_NORETURN to _dbus_assert 2005-01-03 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_sysdeps_test): fix using == on floating point * dbus/dbus-string.c (_dbus_string_insert_alignment): new function 2005-01-02 Havoc Pennington * dbus/dbus-internals.h (_DBUS_ALIGN_OFFSET): new macro 2005-01-01 Havoc Pennington * configure.in: add -Wfloat-equal 2005-01-01 Havoc Pennington * dbus/dbus-sysdeps.h: add _DBUS_DOUBLES_BITWISE_EQUAL macro, for a variety of reasons '==' doesn't do this. 2004-12-31 Havoc Pennington * dbus/dbus-string.c (_dbus_string_equal_substrings): new function I keep wishing I had 2004-12-30 John (J5) Palmieri * python/dbus.py: s/ACTIVATION_REPLY_ACTIVE/ACTIVATION_REPLY_ACTIVATED 2004-12-30 John (J5) Palmieri * python/dbus_bindings.pyx.in: Change DBUS_ACTIVATION_REPLY_ACTIVATED and DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE to match the values in dbus-protocol.h. Because they are defines and not enums they are not autogenerated. 2004-12-26 John (J5) Palmieri * python/dbus_bindings.pyx.in (bus_activate_service): Bind dbus_bus_activate_service * python/dbus.py (Bus.activate_service): activate a service on the bus. 2004-12-24 Havoc Pennington * test/decode-gcov.c: change to use .gcno and .gcda files, but the file format has also changed and I haven't adapted to that yet * Makefile.am: load .gcno files from latest gcc 2004-12-23 John (J5) Palmieri * Patch from Rob Taylor * python/dbus_bindings.pyx.in (bus_get_unix_user): New lowlevel binding * python/dbus.py (get_unix_user): Added binding to call dbus_bindings.bus_get_unix_user * python/extract.py: Modified the proto_pat regex to handle unsigned long 2004-12-21 Olivier Andrieu * dbus/make-dbus-glib-error-enum.sh: omit the function keyword for better POSIX compliance. 2004-12-19 Havoc Pennington * dbus/dbus-string.c (_dbus_string_insert_4_aligned) (_dbus_string_insert_8_aligned): new functions * dbus/dbus-string.c (_dbus_string_alloc_space): new function 2004-12-18 Havoc Pennington * dbus/dbus-string.c (_dbus_string_validate_ascii): use ISASCII macro * dbus/dbus-message.c: fix a comment, and add a still-unused not-implemented function * dbus/dbus-marshal.h: fix comment * dbus/dbus-internals.h (_DBUS_ISASCII): new macro 2004-12-17 Joe Shaw * mono/DBusType/Byte.cs, mono/DBusType/Int32.cs, mono/DBusType/Int64.cs, mono/DBusType/UInt32.cs, mono/DBusType/UInt64.cs: Use Enum.GetUnderlyingType() instead of Type.UnderlyingSystemType to get the actual system type underneath. This code previously depended on the broken Mono behavior, which was fixed in 1.1.3. 2004-11-27 Havoc Pennington * dbus/dbus-string.h (_dbus_string_get_byte): inline when asserts are disabled (_dbus_string_get_const_data): inline when asserts are disabled * dbus/dbus-message.c: record the _dbus_current_generation of creation so we can complain if dbus_shutdown() is used improperly. Do this only if checks are enabled. * dbus/dbus-connection.c: ditto 2004-11-26 Havoc Pennington * test/glib/test-profile.c: add with_bus mode to profile echoes that go through the bus. * test/glib/run-test.sh: add ability to run test-profile * bus/dbus-daemon-1.1.in: fix to say that SIGHUP causes partial config file reload. 2004-11-26 Havoc Pennington * test/glib/test-profile.c: clean up how the fake_malloc_overhead thing was implemented 2004-11-26 Havoc Pennington * test/glib/test-profile.c: tweak a bit, add support for some made-up minimal malloc overhead with plain sockets, since in real life some sort of buffers are unavoidable thus we could count them in the theoretical best case 2004-11-26 Havoc Pennington * dbus/dbus-message.c (dbus_message_cache_or_finalize): fix bug where I was trying to cache one too many messages 2004-11-26 Havoc Pennington * dbus/dbus-message.c: reimplement message cache as an array which makes the cache about twice as fast and saves maybe 1.5% overall 2004-11-26 Havoc Pennington * dbus/dbus-threads.c (init_global_locks): forgot to put the message cache lock here 2004-11-26 Havoc Pennington * dbus/dbus-message.c (struct DBusMessage): put the locked bit and the "char byte_order" next to each other to save 4 bytes (dbus_message_new_empty_header): reduce preallocation, since the message cache should achieve a similar effect (dbus_message_cache_or_finalize, dbus_message_get_cached): add a message cache that keeps a few DBusMessage around in a pool, another 8% speedup or so. * dbus/dbus-dataslot.c (_dbus_data_slot_list_clear): new function 2004-11-25 Havoc Pennington * dbus/dbus-transport-unix.c (unix_do_iteration): if we're going to write, without reading or blocking, try it before the poll() and skip the poll() if nothing remains to write. This is about a 3% speedup in the echo client/server 2004-11-25 Havoc Pennington The primary change here is to always write() once before adding the write watch, which gives us about a 10% performance increase. * dbus/dbus-transport-unix.c: a number of modifications to cope with removing messages_pending (check_write_watch): properly handle DBUS_AUTH_STATE_WAITING_FOR_MEMORY; adapt to removal of messages_pending stuff (check_read_watch): properly handle WAITING_FOR_MEMORY and AUTHENTICATED cases (unix_handle_watch): after writing, see if the write watch can be removed (unix_do_iteration): assert that write_watch/read_watch are non-NULL rather than testing that they aren't, since they aren't allowed to be NULL. check_write_watch() at the end so we add the watch if we did not finish writing (e.g. got EAGAIN) * dbus/dbus-transport-protected.h: remove messages_pending call, since it resulted in too much inefficient watch adding/removing; instead we now require that the transport user does an iteration after queueing outgoing messages, and after trying the first write() we add a write watch if we got EAGAIN or exceeded our max bytes to write per iteration setting * dbus/dbus-string.c (_dbus_string_validate_signature): add this function * dbus/dbus-server-unix.c (unix_finalize): the socket name was freed and then accessed, valgrind flagged this bug, fix it * dbus/dbus-message.c: fix several bugs where HEADER_FIELD_LAST was taken as the last valid field plus 1, where really it is equal to the last valid field. Corrects some message corruption issues. * dbus/dbus-mainloop.c: verbosity changes * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): handle OOM instead of aborting in one of the test codepaths * dbus/dbus-internals.c (_dbus_verbose_real): fix a bug that caused not printing the pid ever again if a verbose was missing the newline at the end (_dbus_header_field_to_string): add HEADER_FIELD_SIGNATURE * dbus/dbus-connection.c: verbosity changes; (dbus_connection_has_messages_to_send): new function (_dbus_connection_message_sent): no longer call transport->messages_pending (_dbus_connection_send_preallocated_unlocked): do one iteration to try to write() immediately, so we can avoid the write watch. This is the core purpose of this patchset (_dbus_connection_get_dispatch_status_unlocked): if disconnected, dump the outgoing message queue, so nobody will get confused trying to send them or thinking stuff is pending to be sent * bus/test.c: verbosity changes * bus/driver.c: verbosity/assertion changes * bus/dispatch.c: a bunch of little tweaks to get it working again because this patchset changes when/where you need to block. 2004-11-23 Havoc Pennington * test/glib/test-profile.c: modify to accept a plain_sockets argument in which case it will bench plain sockets instead of libdbus, for comparison purposes. 2004-11-22 Havoc Pennington * test/glib/test-profile.c (N_CLIENT_THREADS): run multiple threads for more time, so sysprof can get a grip on it. * dbus/dbus-string.c (_dbus_string_validate_utf8): remove pointless variable 2004-11-13 Havoc Pennington * test/glib/test-profile.c: fix this thing up a bit * dbus/dbus-message.c (dbus_message_new_empty_header): increase preallocation sizes by a fair bit; not sure if this will be an overall performance win or not, but it does reduce reallocs. * dbus/dbus-string.c (set_length, reallocate_for_length): ignore the test hack that forced constant realloc if asserts are disabled, so we can profile sanely. Sprinkle in some _DBUS_UNLIKELY() which are probably pointless, but before I noticed the real performance problem I put them in. (_dbus_string_validate_utf8): micro-optimize this thing a little bit, though callgrind says it didn't help; then special-case ascii, which did help a lot; then be sure we detect nul bytes as invalid, which is a bugfix. (align_length_then_lengthen): add some more _DBUS_UNLIKELY superstition; use memset to nul the padding instead of a manual loop. (_dbus_string_get_length): inline this as a macro; it showed up in the profile because it's used for loop tests and so forth 2004-11-10 Colin Walters * dbus/dbus-spawn.c (check_babysit_events): Handle EINTR, for extra paranoia. 2004-11-09 Colin Walters * dbus/dbus-string.c (_dbus_string_get_length): New function, writes DBusString to C buffer. * dbus/dbus-string.h: Prototype it. * dbus/dbus-message.c (dbus_message_type_to_string): New function, converts message type into C string. * dbus/dbus-message.h: Prototype it. * bus/selinux.c (bus_selinux_check): Take source pid, target pid, and audit data. Pass audit data to avc_has_perm. (log_audit_callback): New function, appends extra audit information. (bus_selinux_allows_acquire_service): Also take service name, add it to audit data. (bus_selinux_allows_send): Also take message type, interface, method member, error name, and destination, and add them to audit data. (log_cb): Initialize func_audit. * bus/selinux.h (bus_selinux_allows_acquire_service) (bus_selinux_allows_send): Update prototypes * bus/services.c (bus_registry_acquire_service): Pass service name to bus_selinux_allows_acquire_service. * bus/bus.c (bus_context_check_security_policy): Pass additional audit data. Move assignment of dest to its own line. 2004-11-07 Colin Walters * dbus/dbus-transport-unix.c (do_authentication): Always initialize auth_completed. 2004-11-07 Colin Walters * bus/bus.c (load_config): Break into three separate functions: process_config_first_time_only, process_config_every_time, and process_config_postinit. (process_config_every_time): Move call of bus_registry_set_service_context_table into process_config_postinit. (process_config_postinit): New function, does any processing that needs to happen late in initialization (and also on reload). (bus_context_new): Instead of calling load_config, open config parser here and call process_config_first_time_only and process_config_every_time directly. Later, after we have forked but before changing UID, invoke bus_selinux_full_init, and then call process_config_postinit. (bus_context_reload_config): As in bus_context_new, load parse file inside here, and call process_config_every_time and process_config_postinit. * bus/services.h, bus/services.c (bus_registry_set_service_context_table): Rename from bus_registry_set_sid_table. Take string hash from config parser, and convert them here into SIDs. * bus/config-parser.c (struct BusConfigParser): Have config parser only store a mapping of service->context string. (merge_service_context_hash): New function. (merge_included): Merge context string hashes instead of using bus_selinux_id_table_union. (bus_config_parser_new): Don't use bus_selinux_id_table_new; simply create a new string hash. (bus_config_parser_unref): Unref it. (start_selinux_child): Simply insert strings into hash, don't call bus_selinux_id_table_copy_over. * bus/selinux.h, bus/selinux.c (bus_selinux_id_table_union) (bus_selinux_id_table_copy_over): Delete. 2004-11-03 Colin Walters * bus/selinux.c (bus_selinux_pre_init): Kill some unused variables. 2004-11-03 Colin Walters * bus/test-main.c (test_pre_hook): Fix test logic, thanks Joerg Barfurth . 2004-11-02 Colin Walters * bus/selinux.c (bus_selinux_init): Split into two functions, bus_selinux_pre_init and bus_selinux_post_init. (bus_selinux_pre_init): Just determine whether SELinux is enabled. (bus_selinux_post_init): Do everything else. * bus/main.c (main): Call bus_selinux_pre_init before parsing config file, and bus_selinux_post_init after. This ensures that we don't lose the policyreload notification thread that bus_selinux_init created before forking previously. * bus/test-main.c (test_pre_hook): Update for split. 2004-10-31 Owen Fraser-Green Patch from Johan Fischer * mono/doc/Makefile.am (install-data-local): Added directory install for DESTDIR 2004-10-29 Colin Walters * dbus/dbus-sysdeps.h (_dbus_become_daemon): Also take parameter for fd to write pid to. * dbus/dbus-sysdeps.c (_dbus_become_daemon): Implement it. * bus/bus.c (bus_context_new): Pass print_pid_fd to _dbus_become_daemon (bug #1720) 2004-10-29 Colin Walters Patch from Ed Catmur * mono/doc/Makefile.am (install-data-local): Handle DESTDIR. 2004-10-29 Colin Walters * bus/.cvsignore, qt/.cvsignore: Update. 2004-10-29 Colin Walters Patch from Kristof Vansant * configure.in: Detect Slackware. * bus/Makefile.am (SCRIPT_IN_FILES): Add rc.messagebus.in. * bus/rc.messagebus.in: New file. 2004-10-29 Colin Walters * tools/dbus-monitor.c (filter_func): Return DBUS_HANDLER_RESULT_HANDLED in filter function for now. See: http://freedesktop.org/pipermail/dbus/2004-August/001433.html 2004-10-29 Colin Walters Patch from Matthew Rickard * bus/services.c (bus_registry_acquire_service): Correctly retrieve service name from DBusString for printing. 2004-10-29 Colin Walters * dbus/dbus-glib.h: Update documentation to not refer to internal APIs. 2004-10-27 Joe Shaw * mono/Arguments.cs (GetDBusTypeConstructor): type.UnderlyingSystemType will return "System.Byte" if you do it on "byte[]", which is not what we want. So check the type.IsArray property and use System.Array instead. 2004-10-25 John (J5) Palmieri * dbus/dbus-sysdeps.c (fill_user_info): On errors do not free the DBusUserInfo structure since this is passed into the function. This would cause a double free when the function that allocated the structure would try to free it when an error occured. * (bus/session.conf.in, bus/Makefile.am, dbus/configure.in): use /usr/share/dbus-1/services instead of /usr/lib/dbus-1.0/services for service activation to avoid 32bit/64bit parallel install issues 2004-10-21 Colin Walters * AUTHORS: Fix my email address, the @gnu.org one has been bouncing for some time. Also add J5. 2004-10-21 Colin Walters * dbus/dbus-transport-unix.c (do_authentication): Return authentication status to callers. (unix_handle_watch): If we completed authentication this round, don't do another read. Instead wait until the next iteration, after we've read any pending data in the auth buffer. (unix_do_iteration): Ditto. (unix_handle_watch): Updated for new do_authentication prototype. 2004-10-18 Colin Walters * bus/selinux.c (bus_selinux_enabled): Handle --disable-selinux case. 2004-10-18 Colin Walters * bus/selinux.h: Add bus_selinux_enabled. * bus/selinux.c (bus_selinux_enabled): Implement it. * bus/config-parser.c (struct include): Add if_selinux_enabled member. (start_busconfig_child): Parse if_selinux_enabled attribute for include. (bus_config_parser_content): Handle it. * bus/session.conf.in, bus/system.conf.in: Add inclusion of context mapping to default config files; conditional on SELinux being enabled. * doc/busconfig.dtd: Add to if_selinux_enabled to default DTD. * test/data/invalid-config-files/badselinux-1.conf, test/data/invalid-config-files/badselinux-2.conf: Test files for bad syntax. 2004-10-17 Colin Walters * dbus/dbus-memory.c (_dbus_initialize_malloc_debug, check_guards) (dbus_malloc, dbus_malloc0, dbus_realloc): Fix up printf format specifier mismatches. 2004-10-07 Olivier Andrieu * dbus/dbus-sysdeps.c (_dbus_file_get_contents): fix an incorrect format string. * glib/dbus-dbus-gmain.c (dbus_g_bus_get): do not mangle NULL pointer (bug #1540, Leonardo Boiko). 2004-09-28 Jon Trowbridge * mono/BusDriver.cs: Changed BusDriver struct to remove the ServiceCreated and ServiceDeleted events and replace them with the new ServiceOwnerChanged event. * mono/example/BusListener.cs: Added a new example program, which listens for and reports any ServiceOwnerChanged events on the bus driver. * mono/example/Makefile.am (DESTDIR): Build changes for the new BusListener.cs example. 2004-09-27 Olivier Andrieu * bus/signals.c (bus_match_rule_parse): validate the components of match rules (bug #1439). * dbus/dbus-bus.c (dbus_bus_add_match): add a missing OOM test. 2004-09-24 Olivier Andrieu * doc/dbus-specification.xml: document ServiceOwnerChanged signal. * bus/driver.c, bus/driver.h, bus/services.c: Use ServiceOwnerChanged signal instead of ServiceCreated and ServiceDeleted. * bus/dispatch.c: update testcase for the new signal. 2004-09-20 Jon Trowbridge Patch from Nat Friedman * mono/Makefile.am: A number of small build fixes to allow "make distcheck" to succeed. * mono/example/Makefile.am: "make distcheck" fixes. * mono/AssemblyInfo.cs.in: When signing the assembly, look for the key in @srcdir@. * test/Makefile.am: "make distcheck" fixes. 2004-09-17 Olivier Andrieu * dbus/dbus-sysdeps.c (_dbus_user_at_console): fix memleak in OOM. * doc/busconfig.dtd: update the DTD for the at_console attribute. * bus/driver.c (bus_driver_handle_hello): correctly handle Hello messages after the first one (bug #1389). * bus/dispatch.c (check_double_hello_message): add a test case for the double hello message bug. (check_existent_service_activation): fix check of spawning error. 2004-09-16 David Zeuthen * python/dbus_bindings.pyx.in: Add support for int64 and uint64 2004-09-12 David Zeuthen Patch from Kay Sievers * bus/bus.c (bus_context_new): * bus/bus.h: * bus/main.c (usage) (main): Add commandline option --nofork to override configuration file setting. 2004-09-09 Olivier Andrieu * dbus/dbus-*.h: remove the ; after DBUS_(BEGIN|END)_DECLS. Some C compilers don't like it (bug #974). 2004-09-04 Harald Fernengel * qt/connection.*: Applied patch by Jérôme Lodewyck to integrate an existing connection into the Qt eventloop 2004-08-30 Jon Trowbridge * mono/BusDriver.cs: Added. This is a class for interacting with the org.freedesktop.DBus service. * mono/Message.cs: Added a mechanism to expose the message that is currently being dispatched via the static Message.Current property. Added Message.Sender and Message.Destination properties. * mono/Handler.cs: Expose the dispatched message via Message.Current when handling method calls. * mono/Service.cs: Expose the dispatched message via Message.Current when handling signal emissions. * mono/Connection.cs: Bind dbus_bus_get_base_service via the Connection.BaseService property. 2004-08-28 Havoc Pennington * dbus/dbus-userdb.c (_dbus_is_console_user): remove unused variable More fixes from Steve Grubb * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix fd leak (_dbus_listen_tcp_socket): fix fd leak * dbus/dbus-spawn.c (read_pid, read_ints): move the "again:" for EINTR to a bit lower in the code 2004-08-26 Jon Trowbridge * bus/driver.c (bus_driver_handle_service_exists): Respond with TRUE if we are inquiring about the existence of the built-in org.freedesktop.DBus service. 2004-08-25 John Palmieri * bus/config-parser.c: (struct PolicyType): Add POLICY_CONSOLE (struct Element.d.policy): s/gid_or_uid/gid_uid_or_at_console (start_busconfig_child): Sets up console element when is encountered in a policy file (append_rule_from_element): Convert console elements to console rules. * bus/policy.c: (bus_policy_create_client_policy): Add console rules to the client policy based on if the client is at the console (bus_policy_append_console_rule): New function for adding a console rule to a policy (bus_policy_merge): Handle console rule merging * dbus/dbus-sysdeps.h: Added the DBUS_CONSOLE_DIR constant where we check for console user files * dbus/dbus-sysdeps.c: (_dbus_file_exists): New function which checks if the given file exists (_dbus_user_at_console): New function which does the system specific process of checking if the user is at the console * dbus/dbus-userdb.c: (_dbus_is_console_user): New function converts a UID to user name and then calls the system specific _dbus_user_at_console to see if the user is at the console and therefor a console user 2004-08-25 Olivier Andrieu * bus/config-parser.c (set_limit): * bus/dbus-daemon-1.1.in: * test/data/valid-config-files/many-rules.conf: set the max_match_rules_per_connection limt from the config file. * doc/busconfig.dtd: update the DTD. * bus/driver.c: remove some unused variables. 2004-08-24 Mikael Hallendal * dbus/dbus-glib-lowlevel.h: Removed dbus_bus_get_with_g_main since it's been replaced by dbus_g_bus_get 2004-08-23 Colin Walters Updated SELinux support from Matthew Rickard * bus/selinux.h: Prototype bus_selinux_get_policy_root. * bus/selinux.c: Create a thread for policy reload notification. (bus_selinux_get_policy_root): Implement. * bus/config-parser.c (start_busconfig_child) (bus_config_parser_content): Support SELinux-root relative inclusion. * configure.in : Add -lpthread. * bus/test-main.c (test_pre_hook, test_post_hook): New. (test_post_hook): Move memory checking into here. (test_pre_hook, test_post_hook): Move SELinux checks in here, but conditional on a DBUS_TEST_SELINUX environment variable. Unfortunately we can't run the SELinux checks as a normal user, since they won't have any permissions for /selinux. So this will have to be tested manually for now, until we have virtualization for most of libselinux. 2004-08-23 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_change_identity): add setgroups() to drop supplementary groups, suggested by Steve Grubb 2004-08-20 Colin Walters * bus/config-parser.c (start_busconfig_child): Remove some unused variables. * bus/selinux.c (bus_selinux_id_table_insert): Avoid compiler warning. 2004-08-17 Joe Shaw * configure.in: If --enable-mono is passed in, if we can't find mono error out. * mono/Makefile.am: Use /gacutil to install assemblies into the GAC and not /root. 2004-08-12 Havoc Pennington * NEWS: update for 0.22 * configure.in: release 0.22 2004-08-11 Colin Walters * tools/dbus-send.c (main, usage): Add --reply-timeout argument. 2004-08-10 Olivier Andrieu * bus/bus.c (process_config_first_time_only): get rid of an unused DBusError that was causing a memoy leak (bug #989). * dbus/dbus-keyring.c, dbus/dbus-message.c: fix compilation on Solaris/Forte C (bug #974) * bus/main.c (main): plug two minuscule memleaks. 2004-08-10 Havoc Pennington * doc/dbus-tutorial.xml: add some more info on GLib bindings 2004-08-09 Havoc Pennington * COPYING: switch to Academic Free License version 2.1 instead of 2.0, to resolve complaints about patent termination clause. 2004-07-31 John (J5) Palmieri * README: added documentation for the --enable-python configure switch. 2004-07-31 Olivier Andrieu * bus/config-parser.c (bus_config_parser_new): fix an invalid _unref in the SELinux support. * doc/busconfig.dtd: update DTD for SELinux support. * bus/config-loader-libxml.c: fix error handler and parser initialisation/cleanup. OOM test now works with libxml2 HEAD. * configure.in: remove the warning about libxml2. * dbus/dbus-bus.c: silence doxygen warning. 2004-07-31 Colin Walters * configure.in: Move #error in SELinux check to its own line. 2004-07-31 Olivier Andrieu * dbus/dbus-internals.h (_DBUS_SET_OOM): * bus/utils.h (BUS_SET_OOM): use dbus_error_set_const instead of dbus_error_set. * bus/dispatch.c (check_send_exit_to_service): fix the test case, broken by the change in the _SET_OOM macros. 2004-07-31 Colin Walters * bus/selinux.c : Include utils.h to get BUS_SET_OOM. 2004-07-31 Colin Walters * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER to correctly detect DBUS__ACQUIRE_SVC. Also add an AC_MSG_CHECKING. 2004-07-24 Havoc Pennington SELinux support from Matthew Rickard * bus/selinux.c, bus/selinux.h: new file encapsulating selinux functionality * configure.in: add --enable-selinux * bus/policy.c (bus_policy_merge): add FIXME to a comment * bus/main.c (main): initialize and shut down selinux * bus/connection.c: store SELinux ID on each connection, to avoid repeated getting of the string context and converting it into an ID * bus/bus.c (bus_context_get_policy): new accessor, though it isn't used (bus_context_check_security_policy): check whether the security context of sender connection can send to the security context of recipient connection * bus/config-parser.c: add parsing for and * dbus/dbus-transport.c (_dbus_transport_get_unix_fd): to implement dbus_connection_get_unix_fd() * dbus/dbus-connection.c (dbus_connection_get_unix_fd): new function, used by the selinux stuff 2004-07-29 Olivier Andrieu * bus/config-loader-libxml.c: complete the implementation of libxml backend for config file loader. Doesn't work with full OOM test yet. * configure.in: change error when selecting libxml into a warning. * test/data/invalid-config-files: add two non-well-formed XML files. * glib/Makefile.am: libdbus_gtool always uses expat, not libxml. * dbus/dbus-transport-unix.c (unix_handle_watch): do not disconnect in case of DBUS_WATCH_HANGUP, several do_reading() may be necessary to read all the buffer. (bug #894) * bus/activation.c (bus_activation_activate_service): fix a potential assertion failure (bug #896). Small optimization in the case of auto-activation messages. * dbus/dbus-message.c (verify_test_message, _dbus_message_test): add test case for byte-through-vararg bug (#901). patch by Kimmo Hämäläinen. 2004-07-28 Anders Carlsson * python/dbus.py: * python/dbus_bindings.pyx.in: Add dbus.init_gthreads (), allow emit_signal to pass arguments to the signal. 2004-07-24 Havoc Pennington * AUTHORS: add some people, not really comprehensively, let me know if I missed you 2004-07-24 Havoc Pennington * Makefile.am (DIST_SUBDIRS): add DIST_SUBDIRS, problem solved by Owen * test/Makefile.am (DIST_SUBDIRS): here also 2004-07-22 Olivier Andrieu * dbus/dbus-sysdeps.c (fill_user_info): fix inexistent label name, breaking build on Solaris, reported by Farhad Saberi on the ML. * dbus/dbus-message.c (dbus_message_append_args_valist): fix the va_arg invocation to account for integer promotion in the case of DBUS_TYPE_BYTE (unsigned char is promoted to int). (bug #901) * bus/services.c (bus_service_remove_owner): fix bug #902, use _dbus_list_get_first_link, not _dbus_list_get_first. * dbus/dbus-bus.c (dbus_bus_service_exists): plug a memory leak. * dbus/dbus-object-tree.c (free_subtree_recurse): always null handler functions so that the asserts in _dbus_object_subtree_unref do not fail. * dbus/dbus-transport-unix.c (do_reading): _dbus_transport_queue_messages return value is of type dbus_bool_t, not DBusDispatchStatus. 2004-07-19 David Zeuthen * dbus/dbus-protocol.h: Add DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN * bus/dispatch.c: (check_get_connection_unix_user): Debug says GetProperty; but the method is called GetConnectionUnixUser (check_get_connection_unix_process_id): New function (bus_dispatch_test): Actually call check_get_connection_unix_user(); also call check_get_connection_unix_process_id() * bus/driver.c: (bus_driver_handle_get_connection_unix_process_id): New function, handles GetConnectionUnixProcessID on the org.freedesktop.DBus interface * dbus/dbus-auth.c: (handle_server_data_external_mech): Set pid from the credentials obtained from the socket * dbus/dbus-connection.c: (dbus_connection_get_unix_process_id): New function * dbus/dbus-connection.h: Add prototype for dbus_connection_get_unix_process_id * dbus/dbus-transport.c: (_dbus_transport_get_unix_process_id): New function * dbus/dbus-transport.h: Add prototype for _dbus_transport_get_unix_process_id 2004-07-19 Olivier Andrieu * dbus/dbus-message.c: Message counter fix, patch by Christian Hammond 2004-07-18 Seth Nickell * python/dbus.py: * python/dbus_bindings.pyx.in: * python/tests/test-client.py: Add dbus.ByteArray and dbus_bindings.ByteArray types so that byte streams can be passed back. Give jdahlin the heaps of credit that are so rightfully his. 2004-07-12 Seth Nickell * python/dbus.py: Add message argument to the default object_method_handler function. * python/dbus_bindings.pyx.in: Automatically return NIL when passed an empty list (we can't pass back a list since lists are typed and we don't have any idea what type the the client intended the list to be... :-( ) 2004-07-10 Seth Nickell * python/examples/Makefile.am: Fix distcheck breakage caused by new examples. 2004-07-10 Seth Nickell * python/dbus.py: Add "message" argument to service-side dbus.Object methods. This will break existing services written using the python bindings, but will allow extraction of all the message information (e.g. who its from). Add improved "object oriented" signal handling/emission. * python/examples/example-service.py: Nix this example. * python/examples/example-signal-emitter.py: * python/examples/example-signal-recipient.py: Two new examples that show how to emit and receive signals using the new APIs. * python/examples/example-signals.py: * python/examples/gconf-proxy-service.py: * python/examples/gconf-proxy-service2.py: Add "message" argument to service methods. 2004-06-28 Kay Sievers * bus/driver.c (bus_driver_handle_get_connection_unix_user) * dbus/bus.c (dbus_bus_get_unix_user) * doc/dbus-specification.xml: implement GetConnectionUnixUser method of org.freedesktop.DBus interface. * bus/dispatch.c: test case 2004-06-23 John (J5) Palmieri * python/Makefile.am: switched include directory from glib/ to dbus/ since dbus-glib.h moved 2004-06-22 Olivier Andrieu * configure.in: prevent building the gcj stuff and libxml loader since they are broken. 2004-06-20 Havoc Pennington * dbus/dbus-glib-error-enum.h: autogenerate the GError enum codes from the dbus error names * glib/dbus-glib.h: move to subdir dbus/ since it's included as dbus/dbus-glib.h and that breakage is now visible due to including dbus/dbus-glib.h in dbus-glib-lowlevel.h * glib/dbus-glib.h: s/gproxy/g_proxy/ * dbus/dbus-shared.h: new header to hold stuff shared with binding APIs * dbus/dbus-protocol.h (DBUS_ERROR_*): move errors here rather than dbus-errors.h * glib/dbus-glib.h (dbus_set_g_error): move to dbus-glib-lowlevel.h * glib/dbus-glib.h: remove dbus/dbus.h from here; change a bunch of stuff to enable this * dbus/dbus-glib-lowlevel.h: put dbus/dbus.h here * a bunch of other changes with the same basic "separate glib bindings from dbus.h" theme 2004-06-10 Owen Fraser-Green * dbus-sharp.pc.in: Removed glib-sharp inclusion in Libs. * python/examples/Makefile.am: Fixed typo in EXTRA_DIST. 2004-06-09 Olivier Andrieu * bus/driver.c, dbus/dbus-bus.c: use BOOLEAN instead of UINT32 for the reply value of the ServiceExists message. 2004-06-07 John (J5) Palmieri * python/dbus_bindings.pyx.in: No longer need to parse path elements and pass them as arrays of strings. The C API now accepts plain path strings. (_build_parsed_path): removed 2004-06-07 Havoc Pennington * doc/TODO: remove auto-activation item since it's done; sort items by importance/milestone 2004-06-07 Havoc Pennington * dbus/dbus-message-builder.c (_dbus_message_data_load): append random signature when using REQUIRED_FIELDS (this hack won't work in the long term) * dbus/dbus-message.c: change the signature to be a header field, instead of message->signature special-case string. Incremental step forward. Then we can fix up code to send the signature in the message, then fix up code to validate said signature, then fix up code to not put the typecodes inline, etc. (load_one_message): don't make up the signature after the fact (decode_header_data): require signature field for the known message types * dbus/dbus-marshal.c (_dbus_marshal_string_len): new * dbus/dbus-protocol.h: add DBUS_HEADER_FIELD_SIGNATURE 2004-06-07 Owen Fraser-Green * mono/DBusType/ObjectPath.cs: Renamed PathName argument to Path * mono/Handler.cs: Updated to follow new path argument for (un-)registering objects. * mono/example/Makefile.am: * mono/Makefile.am: * configure.in: Bumped required version for mono and use new -pkg syntax for deps 2004-06-05 Olivier Andrieu * dbus/dbus-connection.h, dbus/dbus-connection.c: have object path registration functions take the path argument as char* instead of char**. * dbus/dbus-marshal.h, dbus/dbus-marshal.c (_dbus_decompose_path): split off the path decompostion part of _dbus_demarshal_object_path. Some misc. fixes to silence compiler warnings. * glib/dbus-gobject.c, test/test-service.c: update accordingly. 2004-06-02 Kristian Høgsberg * dbus/dbus-auth.c: Rewrite auth protocol handling to use a state machine approach. A state is implemented as a function that handles incoming events as specified for that state. * doc/dbus-specification.xml: Update auth protocol state machine specification to match implementation. Remove some leftover base64 examples. 2004-06-02 Kristian Høgsberg * glib/dbus-gproxy.c, glib/dbus-gmain.c, dbus/dbus-string.c, dbus/dbus-object-tree.c, dbus/dbus-message.c: add comments to quiet doxygen. * Doxyfile.in: remove deprecated options. * dbus/dbus-message-handler.c, dbus/dbus-message-handler.h, glib/test-thread.h, glib/test-thread-client.c, glib/test-thread-server.c, glib/test-profile.c, glib/test-dbus-glib.c: remove these unused files. 2004-06-01 Olivier Andrieu * dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock): fix dispatch for non-fallback handlers (bug #684). (_dbus_object_subtree_new): initialize invoke_as_fallback field. (find_subtree_recurse): report wether the returned subtree is an exact match or a "fallback" match higher up in the tree. (object_tree_test_iteration): update test case. 2004-06-01 Seth Nickell * python/dbus_bindings.pyx.in: * python/tests/test-client.py: Round off basic type support. Add dicts (yay!), and remaining array types. Make MessageIter more general so it works for dicts too. Mark all loop variables as C integers. 2004-05-31 Havoc Pennington * glib/dbus-gidl.c (method_info_add_arg): keep args sorted with "in" before "out" * glib/dbus-gobject.c (dbus_type_to_string): move to dbus-gutils.c * glib/dbus-glib-tool.c (main): set up to have a --self-test option that runs the tests, and start filling in some code including for starters just dumping the interfaces to stdout * glib/Makefile.am (INCLUDES): define DBUS_LOCALEDIR * test/data/valid-introspection-files/lots-of-types.xml: test of an example introspection file * glib/dbus-gparser.c (parser_check_doctype): doctype should be "node" (I think...) 2004-05-31 Seth Nickell * python/dbus_bindings.pyx.in: * python/tests/test-client.py: Test Suite: 1 Python Bindings: 0 Fix string array memory trashing bug... oops... 2004-05-30 Seth Nickell * python/dbus.py: Add a nicer-but-less-flexible alternate API for handling calls to virtual objects in dbus.ObjectTree. Screw up the argument order to the dbus.Object constructor for consistency with dbus.ObjectTree (and to make dbus_methods optional for future extension) * python/examples/Makefile.am: * python/examples/gconf-proxy-service.py: * python/examples/gconf-proxy-service2.py: Alternate implementation of gconf-proxy-service using the nicer dbus.ObjectTree API. * python/examples/example-service.py: * python/tests/test-server.py Reverse the argument order to deal with dbus.Object constructor changes. 2004-05-30 Seth Nickell * python/examples/example-client.py: * python/examples/example-service.py: Take it back. Lists seem to work but they're broken in the test suite. Make the base examples use lists (works fine). 2004-05-30 Seth Nickell * python/dbus_bindings.pyx.in: * python/tests/test-client.py: Add some more tests and fix errors that crop up. Unfortunately, currently it seems like marshalling and unmarshalling of lists is completely broken :-( 2004-05-30 Seth Nickell * python/dbus_bindings.pyx.in: Add support for ObjectPath type. * python/dbus.py: Refactor message handling code to a common function. * python/tests/test-client.py: * python/tests/test-server.py: Add tests that check to make sure values of all types can be echoed from a service w/o mangling. 2004-05-29 Seth Nickell * python/dbus.py: Add ObjectTree class which allows implementation of trees of "virtual" objects. Basically the python wrapper for "register_fallback". * python/examples/Makefile.am * python/examples/gconf-proxy-client.py: * python/examples/gconf-proxy-service.py: Implement a simple GConf proxy service that supports get/set on string and int GConf keys using the ObjectTree. 2004-05-29 Seth Nickell * python/dbus.py: * python/examples/example-client.py: * python/examples/example-service.py: * python/examples/list-system-services.py: Add SessionBus, SystemBus and ActivationBus classes so you don't need to know the special little BUS_TYPE flag. 2004-05-29 Havoc Pennington * bus/config-parser.c (process_test_valid_subdir): temporarily stop testing config parser OOM handling, since expat has issues http://freedesktop.org/pipermail/dbus/2004-May/001153.html * bus/dbus-daemon-1.1.in: change requested_reply to send_requested_reply/receive_requested_reply so we can send the replies, not just receive them. * bus/config-parser.c: parse the new send_requested_reply/receive_requested_reply * bus/policy.c (bus_client_policy_check_can_send): add requested_reply argument and use it * bus/bus.c (bus_context_check_security_policy): pass through requested_reply status to message send check * bus/system.conf.in: adapt to requested_reply change 2004-05-28 Havoc Pennington * test/glib/test-service-glib.c (main): remove unused variable * glib/dbus-gidl.c (base_info_ref): fix a silly compiler warning * dbus/dbus-auth.h (enum): remove AUTHENTICATED_WITH_UNUSED_BYTES from the enum, no longer in use. * dbus/dbus-sysdeps.h: include config.h so DBUS_VA_COPY actually works right. * dbus/dbus-message.c: add various _dbus_return_val_if_fail for whether error_name passed in is a valid error name. 2004-05-28 John (J5) Palmieri * dbus/dbus-message.c (dbus_message_get_args): Added support for OBJECT_PATH and OBJECT_PATH_ARRAY 2004-05-28 Seth Nickell * python/examples/Makefile.am: Forget to add Makefile.am. Do not pass go. 2004-05-28 Michael Meeks * glib/dbus-gvalue.c (dbus_gvalue_marshal, dbus_gvalue_demarshal): fix no int64 case. * dbus/dbus-string.c (_dbus_string_parse_basic_type): impl. * dbus/dbus-message.c (_dbus_message_iter_get_basic_type), (_dbus_message_iter_get_basic_type_array): impl. drastically simplify ~all relevant _get methods to use these. (_dbus_message_iter_append_basic_array), (dbus_message_iter_append_basic): impl drastically simplify ~all relevant _append methods to use these. * dbus/dbus-message-builder.c (parse_basic_type) (parse_basic_array, lookup_basic_type): impl. (_dbus_message_data_load): prune scads of duplicate / cut & paste coding. * dbus/dbus-marshal.c (_dbus_demarshal_basic_type_array) (_dbus_demarshal_basic_type): implement, (demarshal_and_validate_len/arg): beef up debug. (_dbus_marshal_basic_type, _dbus_marshal_basic_type_array): impl. 2004-05-27 Seth Nickell * configure.in: * python/Makefile.am: Include the example python apps in the tarball. * python/examples/list-system-services.py Add a python new example that fetches the list of services from the system bus. 2004-05-27 Seth Nickell * python/dbus.py: * python/dbus_bindings.pyx.in: Fix failure to notify that a signal was not handled, resulted in hung functions. 2004-05-25 Colin Walters * tools/dbus-monitor.c (main): Monitor all types of messages. 2004-05-23 Owen Fraser-Green * mono/Handler.cs, mono/Service.cs: Added UnregisterObject method which unregisters the object path and disposes the handler. 2004-05-23 Kristian Høgsberg Patch from Timo Teräs (#614): * dbus/dbus-message.c (dbus_message_iter_get_args_valist): Swap operands to && so we call dbus_message_iter_next () for the last argument also. 2004-05-21 Olivier Andrieu * dbus/dbus-object-tree.c (_dbus_object_tree_list_registered_unlock, lookup_subtree): return children even if the requested path isn't registered. (object_tree_test_iteration): test object_tree_list_registered. * configure.in: undefine HAVE_ABSTRACT_SOCKETS instead of defining it to 0. 2004-05-20 Kristian Høgsberg * doc/TODO: Remove resolved items. * bus/expirelist.h (struct BusExpireList): remove unused n_items field. * bus/connection.c (bus_connections_expect_reply): Enforce the per-connection limit on pending replies. Patch from Jon Trowbridge : * bus/main.c (setup_reload_pipe): Added. Creates a pipe and sets up a watch that triggers a config reload when one end of the pipe becomes readable. (signal_handler): Instead of doing the config reload in our SIGHUP handler, just write to the reload pipe and let the associated watch handle the reload when control returns to the main loop. * bus/driver.c (bus_driver_handle_reload_config): Added. Implements a ReloadConfig method for requesting a configuration file reload via the bus driver. 2004-05-19 Owen Fraser-Green * HACKING: Updated release instructions concerning the wiki page. 2004-05-18 Kristian Høgsberg * dbus/dbus-auth.c (client_try_next_mechanism): Remove logic to filter against auth->allowed_mechs; we only add allowed mechs in record_mechanisms(). * dbus/dbus-auth-script.c (_dbus_auth_script_run): Add an ALLOWED_MECHS to auth-script format so we can set the list of allowed mechanisms. * data/auth/client-out-of-mechanisms.auth-script: New test to check client disconnects when it is out of mechanisms to try. * dbus/dbus-auth.c (process_command): Remove check for lines longer that 1 MB; we only buffer up maximum 16 kB. * dbus/dbus-transport.c, dbus/dbus-transport-unix.c, dbus/dbus-auth-script.c, dbus/dbus-auth.c, dbus/dbus-auth.h: Remove auth state AUTHENTICATED_WITH_UNUSED_BYTES, instead always assume there might be unused bytes. * dbus/dbus-auth.c (_dbus_auth_do_work): Remove check for client-out-of-mechs, it is handled in process_reject(). Move check for max failures to send_rejected(), as it's a server-only thing. * dbus/dbus-auth.c: Factor out protocol reply code into functions send_auth(), send_data(), send_rejected(), send_error(), send_ok(), send_begin() and send_cancel(). 2004-05-17 Kristian Høgsberg Remove base64 encoding, replace with hex encoding. Original patch from trow@ximian.com, added error handling. * dbus/dbus-string.c (_dbus_string_base64_encode) (_dbus_string_base64_decode): Remove. (_dbus_string_hex_decode): Add end_return argument so we can distinguish between OOM and invalid hex encoding. (_dbus_string_test): Remove base64 tests and add test case for invalid hex. * dbus/dbus-keyring.c, dbus/dbus-auth-script.c, dbus/dbus-auth.c: Replace base64 with hex. * test/data/auth/invalid-hex-encoding.auth-script: New test case for invalid hex encoded data in auth protocol. 2004-05-17 Olivier Andrieu * dbus/dbus-connection.c (check_for_reply_unlocked): plug a memory leak. 2004-05-15 Owen Fraser-Green * mono/dbus-sharp.dll.config.in: Added for GAC * mono/dbus-sharp.snk: Added for GAC * mono/Assembly.cs.in: Added for GAC * mono/Makefile.am: Changes for GAC installation * configure.in: Added refs for dbus-sharp.dll.config.in and Assembly.cs.in. More fixes for mono testing * mono/example/Makefile.am: Changed var to CSC * Makefile.am: Changed flag name to DBUS_USE_CSC 2004-05-15 Owen Fraser-Green * mono/Makefile.am: Added SUBDIRS for docs. Changed SUBDIRS order * mono/doc/*: Added documentation framework * configure.in: Added monodoc check * README: Added description of mono configure flags 2004-05-11 John (J5) Palmieri : * doc/dbus-specification.xml: Added a "Required" column to the header fields table and changed the "zero or more" verbage in the above paragraph to read "The header must contain the required named header fields and zero or more of the optional named header fields". * test/data/invalid-messages/*.message: Added the required PATH named header field to the tests so that they don't fail on 'Missing path field' 2004-05-07 John (J5) Palmieri * python/dbus-bindings.pyx.in: Stopped the bindings from trashing the stack by implicitly defining variable and parameter types and removing the hack of defining C pointers as python objects and later casting them. 2004-05-02 Owen Fraser-Green * mono/Makefile.am: Removed test-dbus-sharp.exe from all target 2004-05-01 Owen Fraser-Green * mono/DBusType/Dict.cs: Handle empty dicts * mono/DBusType/Array.cs: Handle empty arrays * mono/Arguments.cs: Handle empty arguments 2004-04-30 Owen Fraser-Green * dbus-sharp.pc.in: Modified to include include Libs and Requires field 2004-04-25 Kristian Høgsberg * test/data/valid-messages/standard-*.message: Update message test scripts to new header field names. 2004-04-22 John (J5) Palmieri * test/break-loader.c (randomly_do_n_things): tracked down buffer overflow to times_we_did_each_thing array which would chop off the first character of the failure_dir string. Increased the size of the array to 7 to reflect the number of random mutation functions we have. 2004-04-21 Kristian Høgsberg * dbus/dbus-server-unix.c (unix_finalize): Don't unref unix_server->watch here, it is unreffed in disconnect. (_dbus_server_new_for_tcp_socket): convert NULL host to "localhost" here so we don't append NULL to address. * dbus/dbus-server.c (_dbus_server_test): Add test case for various addresses, including tcp with no explicit host. 2004-04-21 Olivier Andrieu * dbus/dbus-message.c (decode_header_data, decode_string_field): fix incorrect setting of .name_offset in the HeaderField (it was off by two bytes, positioned right after the name and typecode) * bus/bus.c (bus_context_new, bus_context_unref): test before calling dbus_server_free_data_slot and _dbus_user_database_unref in case of an error. * tools/Makefile.am: add $(DBUS_GLIB_TOOL_LIBS), xml libs needed by libdbus-gtool. 2004-04-19 Kristian Høgsberg * dbus/dbus-transport-unix.c (unix_do_iteration): Rewrite to use _dbus_poll() instead of select(). 2004-04-15 Jon Trowbridge * bus/main.c (signal_handler): Reload the configuration files on SIGHUP. (main): Set up our SIGHUP handler. * bus/bus.c (struct BusContext): Store the config file, user and fork flag in the BusContext. (process_config_first_time_only): Added. Contains the code (previously in bus_context_new) for setting up the BusContext from the BusConfigParser that should only be run the first time the config files are read. (process_config_every_time): Added. Contains the code (previously in bus_context_new) for setting up the BusContext from the BusConfigParser that should be run every time the config files are read. (load_config): Added. Builds a BusConfigParser from the config files and passes the resulting structure off to process_config_first_time_only (assuming this is the first time) and process_config_every_time. (bus_context_new): All of the config-related code has been moved to process_config_first_time_only and process_config_every_time. Now this function just does the non-config-related initializations and calls load_config. (bus_context_reload_config): Added. 2004-04-15 Olivier Andrieu * bus/driver.c (bus_driver_handle_get_service_owner): implement a GetServiceOwner method. * doc/dbus-specification.xml: document it. * dbus/dbus-errors.h: add a 'ServiceHasNoOwner' error. * glib/dbus-gproxy.c (dbus_gproxy_new_for_service_owner): implement, using the bus GetServiceOwner method. * test/glib/test-dbus-glib.c: use dbus_gproxy_new_for_service_owner so that we can receive the signal. 2004-04-15 John (J5) Palmieri * dbus/dbus-internals.c, dbus/dbus-message-builder.c, dbus/dbus-message.c, dbus/dbus-protocol.h (DBUS_HEADER_FIELD_SERVICE): renamed DBUS_HEADER_FIELD_DESTINATION * dbus/dbus-internals.c, dbus/dbus-message-builder.c, dbus/dbus-message.c, dbus/dbus-protocol.h (DBUS_HEADER_FIELD_SENDER_SERVICE): renamed DBUS_HEADER_FIELD_SENDER * dbus/dbus-internals.c (_dbus_header_field_to_string): DBUS_HEADER_FIELD_DESTINATION resolves to "destination" DBUS_HEADER_FIELD_SENDER resolves to "sender" * doc/dbus-specification.xml (Header Fields Table): s/SERVICE/DESTINATION s/SENDER_SERVICE/SENDER 2004-04-14 Olivier Andrieu * test/glib/test-dbus-glib.c (timed_exit): fail the test after a few seconds. 2004-04-13 Michael Meeks * glib/dbus-gobject.c (handle_introspect): split out (introspect_properties): this. (handle_introspect): implement this. * test/glib/Makefile.am: use the absolute path so the bus daemon's chdir ("/") doesn't kill us dead. * configure.in: subst ABSOLUTE_TOP_BUILDDIR 2004-04-12 Jon Trowbridge * bus/config-parser.c (struct BusConfigParser): Added included_files field. (seen_include): Added. Checks whether or not a file has already been included by any parent BusConfigParser. (bus_config_parser_new): Copy the parent's included_files. (include_file): Track which files have been included, and fail on circular inclusions. (process_test_valid_subdir): Changed printf to report if we are testing valid or invalid conf files. (all_are_equiv): Changed printf to be a bit clearer about what we are actually doing. (bus_config_parser_test): Test invalid configuration files. 2004-04-09 Jon Trowbridge * bus/config-parser.c (bus_config_parser_new): Added a 'parent' argument. If non-null, the newly-constructed BusConfigParser will be initialized with the parent's BusLimits instead of the default values. (include_file): When including a config file, pass in the current parser as the parent and then copy the BusLimits from the included BusConfigParser pack to the current parser. (process_test_valid_subdir): Renamed from process_test_subdir. (process_test_equiv_subdir): Added. Walks through a directory, descending into each subdirectory and loading the config files it finds there. If any subdirectory contains two config files that don't produce identical BusConfigParser structs, fail. For now, the BusConfigParser's BusPolicies are not compared. (bus_config_parser_test): Call both process_test_valid_subdir and process_test_equiv_subdir. * bus/config-loader-libxml.c (bus_config_load): Take a parent argument and pass it along to the call to bus_config_parser_new. Also made a few small changes to allow this code to compile. * bus/config-loader-expat.c (bus_config_load): Take a parent argument and pass it along to the call to bus_config_parser_new. * bus/bus.c (bus_context_new): Load the config file with a NULL parent argument. 2004-03-29 Michael Meeks * glib/dbus-gobject.c (introspect_properties): split out, fix mangled 'while' flow control. (introspect_signals): implement. (handle_introspect): update. 2004-03-29 Michael Meeks * glib/dbus-gobject.c (set_object_property): split out / re-work, use the property type, and not the message type(!) (get_object_property): ditto. * glib/dbus-gvalue.c (dbus_gvalue_demarshal), (dbus_gvalue_marshal): make this code re-usable, needed for signals too, also on both proxy and server side. Re-write for more efficiency / readability. 2004-03-29 Michael Meeks * dbus/dbus-message.c (dbus_message_new_error_printf): impl. * dbus/dbus-connection.c (dbus_connection_unregister_object_path): fix warning. * configure.in: fix no-mono-installed situation. 2004-03-27 Havoc Pennington Patch from Timo Teräs: * tools/dbus-send.c (main): if --print-reply, assume type is method call; support boolean type args * dbus/dbus-connection.c (dbus_connection_send_with_reply): fix a bunch of memleak and logic bugs 2004-03-23 Owen Fraser-Green * mono/Arguments.cs: * mono/Introspector.cs: * mono/Handler.cs: * mono/InterfaceProxy.cs: * mono/Message.cs * mono/ProxyBuilder.cs: * mono/Service.cs: Added InterfaceProxy class to avoid building proxies for every object. * dbus-message.h: * dbus-message.c (dbus_message_append_args_valist) (dbus_message_iter_get_object_path) (dbus_message_iter_get_object_path_array) (dbus_message_iter_append_object_path) (dbus_message_iter_append_object_path_array): Added object_path iter functions to handle OBJECT_PATH arguments 2004-03-23 Owen Fraser-Green First checkin of mono bindings. * configure.in: * Makefile.am: Build stuff for the bindings * dbus-sharp.pc.in: Added for pkgconfig 2004-03-21 Havoc Pennington * test/test-service.c (main): remove debug spew 2004-03-21 Olivier Andrieu * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): accept empty arrays * dbus/dbus-message.h, bus/dbus-message.c (dbus_message_iter_init) (dbus_message_iter_init_array_iterator) (dbus_message_iter_init_dict_iterator): return a dbus_bool_t to indicate whether the iterator is empty * dbus/dbus-pending-call.c, dbus/dbus-server.c: silence compiler warnings 2004-03-19 Havoc Pennington * NEWS: 0.21 updates * configure.in: 0.21 * doc/Makefile.am: add all XMLTO usage to DBUS_XML_DOCS_ENABLED * python/Makefile.am: change to avoid dist of dbus_bindings.c so you don't need pyrex to make dist * qt/Makefile.am (libdbus_qt_1_la_SOURCES): add integrator.h to sources; run moc 2004-03-18 Richard Hult * dbus/dbus-message.c (dbus_message_get_auto_activation) (dbus_message_set_auto_activation): Add doxygen docs. 2004-03-16 Richard Hult * bus/activation.c: (bus_activation_service_created), (bus_activation_send_pending_auto_activation_messages), (bus_activation_activate_service): * bus/activation.h: * bus/dispatch.c: (bus_dispatch), (check_nonexistent_service_auto_activation), (check_service_auto_activated), (check_segfault_service_auto_activation), (check_existent_service_auto_activation), (bus_dispatch_test): * bus/driver.c: (bus_driver_handle_activate_service): * bus/services.c: (bus_registry_acquire_service): * dbus/dbus-message.c: (dbus_message_set_auto_activation), (dbus_message_get_auto_activation): * dbus/dbus-message.h: * dbus/dbus-protocol.h: Implement auto-activation. * doc/dbus-specification.xml: Add auto-activation to the spec. 2004-03-12 Olivier Andrieu * dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): fix a bug with CUSTOM types. * dbus/dbus-message.c (message_iter_test, _dbus_message_test): add a unit test for this bug (used to fail). 2004-03-12 Mikael Hallendal * bus/activation.c: (babysitter_watch_callback): notify all pending activations waiting for the same exec that the activation failed. (bus_activation_activate_service): shortcut the activation if we already waiting for the same executable to start up. 2004-03-12 Mikael Hallendal * bus/activation.c: - Added service file reloading. Each service files directory is kept in an hash table in BusActivation and each BusActivationEntry knows what .service-file it was read from. So when you try to activate a service the bus will check if it's been updated, removed or if new .service-files has been installed. - Test code at the bottom for the service file reloading. * bus/test-main.c: (main): * bus/test.h: - added service reloading test. * dbus/dbus-sysdeps.c: * dbus/dbus-sysdeps.h: (_dbus_delete_directory): Added. 2004-03-08 Michael Meeks * dbus/dbus-connection.c (_dbus_connection_block_for_reply): bail immediately if disconnected, to avoid busy loop. * dbus/dbus-message.c (dbus_message_iter_get_args_valist): cleanup cut/paste/inefficiency. 2004-03-01 David Zeuthen * dbus/dbus-string.c (_dbus_string_append_printf_valist): Fix a bug where args were used twice. This bug resulted in a segfault on a Debian/PPC system when starting the messagebus daemon. Include dbus-sysdeps.h for DBUS_VA_COPY * dbus/dbus-sysdeps.h: Define DBUS_VA_COPY if neccessary. From GLib * configure.in: Check for va_copy; define DBUS_VA_COPY to the appropriate va_copy implementation. From GLib 2004-02-24 Joe Shaw * bus/services.c (bus_registry_acquire_service): We need to pass in the service name to dbus_set_error() to prevent a crash. 2003-12-26 Anders Carlsson * AUTHORS: Reveal my True identity. 2003-12-17 Mikael Hallendal * dbus/dbus-message.c: (dbus_message_append_args_valist): - Added case for DBUS_TYPE_BYTE, patch from Johan Hedberg. 2003-12-13 Mikael Hallendal * doc/TODO: Added not about better error check of configuration files. 2003-12-02 Richard Hult * Update AFL version to 2.0 throughout the source files to reflect the update that was done a while ago. 2003-12-02 Richard Hult * dbus/dbus-message.c (dbus_message_iter_append_dict): Set wrote_dict_key to FALSE on the iter that the dict is appended to, just like when appending other types. Fixes a bug where a dict couldn't be put inside a dict. (dbus_message_iter_append_dict_key): Fix typo in warning message. (message_iter_test, _dbus_message_test): Add test case for dict inside dict. 2003-12-01 David Zeuthen * python/dbus.py: Add the actual message when calling the reciever of a signal such that parameters can be inspected. Add the method remove_signal_receiver 2003-11-26 Mikael Hallendal * bus/*.[ch]: * dbus/*.[ch]: * glib/*.[ch]: Made ref functions return the pointer 2003-11-25 Zack Rusin * qt/integrator.h, qt/integrator.cpp: Adding handling of DBusServer, * qt/server.h, qt/server.cpp, qt/Makefile.am: Adding DBusServer wrappers, * qt/connection.h, qt/connection.cpp: Adjusting to changes in the Integrator and to better fit with the server, 2003-11-24 Zack Rusin * qt/connection.h, qt/connection.cpp: removing initDbus method since the integrator handles it now * qt/integrator.h, qt/integrator.cpp: reworking handling of timeouts, since QTimer wasn't really meant to be used the way DBusTimeout is 2003-11-24 Zack Rusin * qt/integrator.h, qt/integrator.cpp, Makefile.am: Adding Integrator class which integrates D-BUS with the Qt event loop, * qt/connection.h, qt/connection.cpp: Move all the code which was dealing with D-BUS integration to the Integrator class, and start using Integrator, 2003-11-23 Zack Rusin * qt/connection.h, qt/connection.cpp: Adding the DBusConnection wrapper * qt/message.h, qt/message.cpp: updating to the current D-BUS api, switching namespaces to DBusQt, reworking the class, * Makefile.cvs: switching dependencies so that it matches KDE schematics, * qt/Makefile.am: adding connection.{h,cpp} and message.{h,cpp} to the library 2003-11-19 Havoc Pennington * NEWS: update * configure.in: bump version to 0.20 * configure.in (have_qt): add yet another place to look for qt (someone hand trolltech a .pc file...) 2003-11-01 Havoc Pennington * doc/dbus-specification.xml: add state machine docs on the auth protocol; just a first draft, I'm sure it's wrong. 2003-10-28 David Zeuthen * python/dbus_bindings.pyx.in: add get_dict to handle dictionaries return types. Fixup TYPE_* to reflect changes in dbus/dbus-protocol.h 2003-10-28 Havoc Pennington * dbus/dbus-message.c (get_next_field): delete unused function 2003-10-28 Havoc Pennington * bus/expirelist.c (do_expiration_with_current_time): detect failure of the expire_func due to OOM * bus/connection.c (bus_pending_reply_expired): return FALSE on OOM * bus/dispatch.c (check_send_exit_to_service): fix to handle the NoReply error that's now created by the bus when the service exits 2003-10-28 Havoc Pennington * dbus/dbus-message.c (_dbus_message_test): enable and fix the tests for set_path, set_interface, set_member, etc. * dbus/dbus-string.c (_dbus_string_insert_bytes): allow 0 bytes * dbus/dbus-message.c (set_string_field): always just delete and re-append the field; accept NULL for deletion (re_align_fields_recurse): reimplement 2003-10-26 Havoc Pennington * dbus/dbus-connection.c: fix docs to properly describe the disconnected message (_dbus_connection_notify_disconnected): remove this function; we can't synchronously add the disconnected message, we have to do it after we've queued any remaining real messages (_dbus_connection_get_dispatch_status_unlocked): queue the disconnect message only if the transport has finished queueing all its real messages and is disconnected. (dbus_connection_disconnect): update the dispatch status here 2003-10-22 Havoc Pennington * bus/bus.c (bus_context_check_security_policy): fix up assertion * bus/connection.c (bus_transaction_send_from_driver): set the destination to the connection's base service 2003-10-20 Havoc Pennington hmm, make check is currently not passing. * doc/dbus-specification.xml: add requirement that custom type names follow the same rules as interface names. * dbus/dbus-protocol.h: change some of the byte codes, to avoid duplication and allow 'c' to be 'custom'; dict is now 'm' for 'map' * doc/dbus-specification.xml: update type codes to match dbus-protocol.h, using the ASCII byte values. Rename type NAMED to CUSTOM. Add type OBJECT_PATH to the spec. 2003-10-17 Havoc Pennington * bus/driver.c (create_unique_client_name): use "." as separator in base service names instead of '-' * dbus/dbus-string.c (_dbus_string_get_byte): allow getting nul byte at the end of the string * dbus/dbus-internals.h (_DBUS_LIKELY, _DBUS_UNLIKELY): add optimization macros since string validation seems to be a slow point. * doc/dbus-specification.xml: restrict valid service/interface/member/error names. Add test suite code for the name validation. * dbus/dbus-string.c: limit service/interface/member/error names to [0-9][A-Z][a-z]_ * dbus/dbus-connection.c (dbus_connection_dispatch): add missing format arg to verbose spew * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): if not out of memory, return instead of g_error * test/test-service.c (path_message_func): support emitting a signal on request * dbus/dbus-bus.c (init_connections_unlocked): only fill in activation bus type if DBUS_BUS_ACTIVATION was set; default to assuming the activation bus was the session bus so that services started manually will still register. (init_connections_unlocked): fix so that in OOM situation we get the same semantics when retrying the function * test/test-service.c (main): change to use path registration, to test those codepaths; register with DBUS_BUS_ACTIVATION rather than DBUS_BUS_SESSION 2003-10-16 Havoc Pennington * glib/dbus-gtest-main.c: bracket with #ifdef DBUS_BUILD_TESTS * Makefile.am (GCOV_DIRS): remove "test", we don't care about test coverage of the tests (coverage-report.txt): don't move the .da and .bbg files around 2003-10-16 Havoc Pennington * bus/bus.c (struct BusContext): remove struct field I didn't mean to put there 2003-10-16 Havoc Pennington * bus/connection.c (bus_pending_reply_expired): either cancel or execute, not both (bus_connections_check_reply): use unlink, not remove_link, as we don't want to free the link; fixes double free mess * dbus/dbus-pending-call.c (dbus_pending_call_block): fix in case where no reply was received * dbus/dbus-connection.c (_dbus_pending_call_complete_and_unlock): fix a refcount leak * bus/signals.c (match_rule_matches): add special cases for the bus driver, so you can match on sender/destination for it. * dbus/dbus-sysdeps.c (_dbus_abort): print backtrace if DBUS_PRINT_BACKTRACE is set * dbus/dbus-internals.c: add pid to assertion failure messages * dbus/dbus-connection.c: add message type code to the debug spew * glib/dbus-gproxy.c (gproxy_get_match_rule): match rules want sender=foo not service=foo * dbus/dbus-bus.c (dbus_bus_get): if the activation bus is the session bus but DBUS_SESSION_BUS_ADDRESS isn't set, use DBUS_ACTIVATION_ADDRESS instead * bus/activation.c: set DBUS_SESSION_BUS_ADDRESS, DBUS_SYSTEM_BUS_ADDRESS if appropriate * bus/bus.c (bus_context_new): handle OOM copying bus type into context struct * dbus/dbus-message.c (dbus_message_iter_get_object_path): new function (dbus_message_iter_get_object_path_array): new function (half finished, disabled for the moment) * glib/dbus-gproxy.c (dbus_gproxy_end_call): properly handle DBUS_MESSAGE_TYPE_ERROR * tools/dbus-launch.c (babysit): support DBUS_DEBUG_OUTPUT to avoid redirecting stderr to /dev/null (babysit): close stdin if not doing the "exit_with_session" thing * dbus/dbus-sysdeps.c (_dbus_become_daemon): delete some leftover debug code; change DBUS_DEBUG_OUTPUT to only enable stderr, not stdout/stdin, so things don't get confused * bus/system.conf.in: fix to allow replies, I modified .conf instead of .conf.in again. 2003-10-14 David Zeuthen * python/dbus_bindings.pyx.in (MessageIter.get): fixed typo in argtype to arg_type when raising unknown arg type exception. Changed type list to reflect the changes in dbus-protocol.h so the bindings actually work. 2003-10-14 Havoc Pennington * test/decode-gcov.c: support gcc 3.3 also, though gcc 3.3 seems to have a bug keeping it from outputting the .da files sometimes (string_get_string): don't append garbage nul bytes to the string. 2003-10-15 Seth Nickell * python/Makefile.am: Include dbus_h_wrapper.h in the dist tarball. 2003-10-14 Havoc Pennington * bus/bus.c (bus_context_check_security_policy): revamp this to work more sanely with new policy-based requested reply setup * bus/connection.c (bus_transaction_send_from_driver): set bus driver messages as no reply * bus/policy.c (bus_client_policy_check_can_receive): handle a requested_reply attribute on allow/deny rules * bus/system.conf: add * bus/driver.c (bus_driver_handle_message): fix check for replies sent to the bus driver, which was backward. How did this ever work at all though? I think I'm missing something. * dbus/dbus-message.c (decode_header_data): require error and method return messages to have a reply serial field to be valid (_dbus_message_loader_queue_messages): break up this function; validate that reply serial and plain serial are nonzero; clean up the OOM/error handling. (get_uint_field): don't return -1 from this (dbus_message_create_header): fix signed/unsigned bug * bus/connection.c (bus_connections_expect_reply): save serial of the incoming message, not reply serial 2003-10-14 Havoc Pennington * bus/connection.c: implement pending reply tracking using BusExpireList * bus/bus.c (bus_context_check_security_policy): verify that a reply is pending in order to allow a reply to be sent. Deny messages of unknown type. * bus/dbus-daemon-1.1.in: update to mention new resource limits * bus/bus.c (bus_context_get_max_replies_per_connection): new (bus_context_get_reply_timeout): new 2003-10-13 Seth Nickell * python/Makefile.am: Pass "make distcheck": remove a couple files from DIST_FILES that weren't included in the final version. 2003-10-12 Havoc Pennington Added test code that 1) starts an actual bus daemon and 2) uses DBusGProxy; fixed bugs that were revealed by the test. Lots more testing possible, but this is the basic framework. * glib/dbus-gproxy.c (dbus_gproxy_manager_unregister): remove empty proxy lists from the proxy list hash * dbus/dbus-message.c (dbus_message_iter_get_args_valist): add a couple of return_if_fail checks * dbus/dbus-pending-call.c (_dbus_pending_call_new): use dbus_new0 to allocate, so everything is cleared to NULL as it should be. * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): pass source as data to dbus_connection_set_timeout_functions() as the timeout functions expected * test/glib/run-test.sh: add a little script to start up a message bus and run tests using it * tools/dbus-launch.1: updates * tools/dbus-launch.c (main): add --config-file option * tools/dbus-launch.c (main): remove confusing else if (runprog) that could never be reached. * dbus/dbus-message.c (dbus_message_new_method_return) (dbus_message_new_error, dbus_message_new_signal): set the no-reply-expected flag on all these. Redundant, but may as well be consistent. 2003-10-11 Havoc Pennington * test/decode-gcov.c (function_solve_graph): make broken block graph a nonfatal error since it seems to be broken. Need to debug this. * dbus/dbus-marshal.c (_dbus_type_is_valid): new function since we can't just check type > INVALID < LAST anymore * dbus/dbus-message.c (dbus_message_get_signature): new function (dbus_message_has_signature): new function (struct DBusMessage): add signature field (right now it isn't sent over the wire, just generated on the fly) (dbus_message_copy): copy the signature, and init strings to proper length to avoid some reallocs (dbus_message_iter_init_array_iterator): return void, since it can't fail (dbus_message_iter_init_dict_iterator): return void since it can't fail (_dbus_message_loader_queue_messages): add silly temporary hack to fill in message->signature on load * dbus/dbus-protocol.h: change DBUS_TYPE_* values to be ASCII characters, so they are relatively human-readable. 2003-10-11 Havoc Pennington * dbus/dbus-message.c (_dbus_message_test): add more test coverage, but #if 0 for now since they uncover a bug not fixed yet; I think in re_align_field_recurse() (re_align_field_recurse): add FIXME about broken assertion * dbus/dbus-sysdeps.c (_dbus_sysdeps_test): add more test coverage * bus/connection.c: share a couple code bits with expirelist.c * bus/expirelist.h, bus/expirelist.c: implement a generic expire-items-after-N-seconds facility, was going to share between expiring connections and replies, decided not to use for expiring connections for now. * COPYING: include AFL 2.0 (still need to change all the file headers) 2003-10-09 Havoc Pennington * configure.in: define DBUS_HAVE_GCC33_GCOV if we have gcc 3.3. Not that we do anything about it yet. * bus/signals.c (bus_match_rule_parse): impose max length on the match rule text * dbus/dbus-protocol.h: add DBUS_MAXIMUM_MATCH_RULE_LENGTH 2003-10-09 Havoc Pennington Make matching rules theoretically work (add parser). * bus/bus.c (bus_context_check_security_policy): fix up to handle the case where destination is explicitly specified as bus driver and someone else is eavesdropping. * bus/policy.c (bus_client_policy_check_can_receive): fix up definition of eavesdropping and assertion * tools/dbus-send.c (main): use dbus_message_type_from_string * bus/signals.c (bus_match_rule_parse): implement * dbus/dbus-message.c (dbus_message_type_from_string): new * dbus/dbus-errors.h (DBUS_ERROR_MATCH_RULE_INVALID): add 2003-10-02 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): rename from dbus_gproxy_oneway_call * glib/dbus-gmain.c (dbus_connection_setup_with_g_main) (dbus_server_setup_with_g_main): fix to allow calling them more than once on the same args (dbus_bus_get_with_g_main): new function 2003-10-02 Havoc Pennington * doc/dbus-tutorial.xml: write some stuff 2003-09-29 Havoc Pennington * configure.in: split checks for Doxygen from XML docs, check for xmlto * doc/Makefile.am: XML-ify all the docs, and add a blank dbus-tutorial.xml 2003-09-29 Havoc Pennington * Merge dbus-object-names branch. To see the entire patch do cvs diff -r DBUS_OBJECT_NAMES_BRANCHPOINT -r dbus-object-names, it's huuuuge though. To revert, I tagged DBUS_BEFORE_OBJECT_NAMES_MERGE. 2003-09-28 Havoc Pennington * HACKING: update to reflect new server 2003-09-26 Seth Nickell * python/dbus.py: * python/examples/example-signals.py: Start implementing some notions of signals. The API is really terrible, but they sort of work (with the exception of being able to filter by service, and to transmit signals *as* a particular service). Need to figure out how to make messages come from the service we registered :-( * python/dbus_bindings.pyx.in: Removed duplicate message_handler callbacks. 2003-09-25 Havoc Pennington * bus/session.conf.in: fix my mess 2003-09-25 Havoc Pennington * bus/session.conf.in: fix security policy, reported by Seth Nickell 2003-09-25 Seth Nickell * python/examples/example-service.py: Johan notices complete wrong code in example-service, but completely wrong in a way that works exactly the same (!). Johan is confused, how could this possibly work? Example code fails to serve purpose of making things clear. Seth fixes. 2003-09-25 Mark McLoughlin * doc/dbus-specification.sgml: don't require header fields to be 4-byte aligned and specify that fields should be distinguished from padding by the fact that zero is not a valid field name. * doc/TODO: remove re-alignment item and add item to doc the OBJECT_PATH type. * dbus/dbus-message.c: (HeaderField): rename the original member to value_offset and introduce a name_offset member to keep track of where the field actually begins. (adjust_field_offsets): remove. (append_int_field), (append_uint_field), (append_string_field): don't align the start of the header field to a 4-byte boundary. (get_next_field): impl finding the next marhsalled field after a given field. (re_align_field_recurse): impl re-aligning a number of already marshalled fields. (delete_field): impl deleting a field of any type and re-aligning any following fields. (delete_int_or_uint_field), (delete_string_field): remove. (set_int_field), (set_uint_field): no need to re-check that we have the correct type for the field. (set_string_field): ditto and impl re-aligning any following fields. (decode_header_data): update to take into account that the fields aren't 4-byte aligned any more and the new way to distinguish padding from header fields. Also, don't exit when there is too much header padding. (process_test_subdir): print the directory. (_dbus_message_test): add test to make sure a following field is re-aligned correctly after field deletion. * dbus/dbus-string.[ch]: (_dbus_string_insert_bytes): rename from insert_byte and allow the insert of multiple bytes. (_dbus_string_test): test inserting multiple bytes. * dbus/dbus-marshal.c: (_dbus_marshal_set_string): add warning note to docs about having to re-align any marshalled values following the string. * dbus/dbus-message-builder.c: (append_string_field), (_dbus_message_data_load): don't align the header field. * dbus/dbus-auth.c: (process_test_subdir): print the directory. * test/break-loader.c: (randomly_add_one_byte): upd. for insert_byte change. * test/data/invalid-messages/bad-header-field-alignment.message: new test case. * test/data/valid-messages/unknown-header-field.message: shove a dict in the unknown field. 2003-09-25 Seth Nickell * python/dbus.py: * python/dbus_bindings.pyx.in: Handle return values. * python/examples/example-client.py: * python/examples/example-service.py: Pass back return values from the service to the client. 2003-09-24 Seth Nickell * python/dbus.py: Connect Object methods (when you are sharing an object) up... pass in a list of methods to be shared. Sharing all the methods just worked out too weird. You can now create nice Services over the DBus in Python. :-) * python/dbus_bindings.pyx.in: Keep references to user_data tuples passed into C functions so Python doesn't garbage collect on us. Implement MethodReturn and Error subclasses of Message for creating DBusMessage's of those types. * python/examples/example-client.py: * python/examples/example-service.py: Simple example code showing both how create DBus services and objects, and how to use them. 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement (dbus_gproxy_disconnect_signal): implement (dbus_gproxy_manager_remove_signal_match): implement (dbus_gproxy_manager_add_signal_match): implement (dbus_gproxy_oneway_call): implement 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject subclass. This means dropping the transparent thread safety of the proxy; you now need a separate proxy per-thread, or your own locking on the proxy. Probably right anyway. (dbus_gproxy_ref, dbus_gproxy_unref): nuke, just use g_object_ref 2003-09-22 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement 2003-09-21 Seth Nickell First checkin of the Python bindings. * python/.cvsignore: * python/Makefile.am: * python/dbus_bindings.pyx.in: * python/dbus_h_wrapper.h: Pieces for Pyrex to operate on, building a dbus_bindings.so python module for low-level access to the DBus APIs. * python/dbus.py: High-level Python module for accessing DBus objects. * configure.in: * Makefile.am: Build stuff for the python bindings. * acinclude.m4: Extra macro needed for finding the Python C header files. 2003-09-21 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_new): start implementing the proxy manager, didn't get very far. * dbus/dbus-bus.c (dbus_bus_add_match): new (dbus_bus_remove_match): new * glib/dbus-gproxy.c (dbus_gproxy_new_for_service): add a path_name argument; adjust the other not-yet-implemented gproxy constructors to be what I think they should be. 2003-09-21 Havoc Pennington * dbus/dbus-bus.c (dbus_bus_get): set exit_on_disconnect to TRUE by default for message bus connections. * dbus/dbus-connection.c (dbus_connection_dispatch): exit if exit_on_disconnect flag is set and we process the disconnected signal. (dbus_connection_set_exit_on_disconnect): new function 2003-09-21 Havoc Pennington Get matching rules mostly working in the bus; only actually parsing the rule text remains. However, the client side of "signal connections" hasn't been started, this patch is only the bus side. * dbus/dispatch.c: fix for the matching rules changes * bus/driver.c (bus_driver_handle_remove_match) (bus_driver_handle_add_match): send an ack reply from these method calls * glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of arguments, reported by Seth Nickell * bus/config-parser.c (append_rule_from_element): support eavesdrop=true|false attribute on policies so match rules can be prevented from snooping on the system bus. * bus/dbus-daemon-1.1.in: consistently use terminology "sender" and "destination" in attribute names; fix some docs bugs; add eavesdrop=true|false attribute * bus/driver.c (bus_driver_handle_add_match) (bus_driver_handle_remove_match): handle AddMatch, RemoveMatch messages * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get rid of broadcast service concept, signals are just always broadcast * bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c: mostly implement matching rules stuff (currently only exposed as signal connections) 2003-09-21 Mark McLoughlin * doc/dbus-specification.sgml: Change the header field name to be an enum and update the rest of the spec to reference the fields using the conventinal name. * dbus/dbus-protocol.h: update to reflect the spec. * doc/TODO: add item to remove the 4 byte alignment requirement. * dbus/dbus-message.c: Remove the code to generalise the header/body length and serial number header fields as named header fields so we can reference field names using the protocol values. (append_int_field), (append_uint_field), (append_string_field): Append the field name as a byte rather than four chars. (delete_int_or_uint_field), (delete_string_field): reflect the fact that the field name and typecode now occupy 4 bytes instead of 8. (decode_string_field), (decode_header_data): update to reflect protocol changes and move the field specific encoding from decode_string_field() back into decode_header_data(). * dbus/dbus-internals.[ch]: (_dbus_header_field_to_string): Add utility to aid debugging. * dbus/dbus-message-builder.c: (append_string_field), (_dbus_message_data_load): Update to reflect protocol changes; Change the FIELD_NAME directive to HEADER_FIELD and allow it to take the field's conventional name rather than the actual value. * test/data/*/*.message: Update to use HEADER_FIELD instead of FIELD_NAME; Always align the header on an 8 byte boundary *before* updating the header length. 2003-09-15 Havoc Pennington * dbus/dbus-pending-call.c: add the get/set object data boilerplate as for DBusConnection, etc. Use generic object data for the notify callback. * glib/dbus-gparser.c (parse_node): parse child nodes * tools/dbus-viewer.c: more hacking on the dbus-viewer * glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to contain functions shared between the convenience lib and the installed lib * glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add -export-symbols-regex to the GLib library * dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock): fix the locking in here, and add a default handler for Introspect() that just returns sub-nodes. 2003-09-14 Havoc Pennington * glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo rather than gfoo consistent * glib/dbus-gproxy.h: delete for now, move contents to dbus-glib.h, because the include files don't work right since we aren't in the dbus/ subdir. * glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing (dbus_gproxy_end_call): finish (dbus_gproxy_begin_call): finish * glib/dbus-gmain.c (dbus_set_g_error): new * glib/dbus-gobject.c (handle_introspect): include information about child nodes in the introspection * dbus/dbus-connection.c (dbus_connection_list_registered): new function to help in implementation of introspection * dbus/dbus-object-tree.c (_dbus_object_tree_list_registered_and_unlock): new function 2003-09-12 Havoc Pennington * glib/dbus-gidl.h: add common base class for all the foo_info types * tools/dbus-viewer.c: add GTK-based introspection UI thingy similar to kdcop * test/Makefile.am: try test srcdir -ef . in addition to test srcdir = ., one of them should work (yeah lame) * glib/Makefile.am: build the "idl" parser stuff as a convenience library * glib/dbus-gparser.h: make description_load routines return NodeInfo* not Parser* * Makefile.am (SUBDIRS): build test dir after all library dirs * configure.in: add GTK+ detection 2003-09-07 Havoc Pennington * Make Doxygen contented. 2003-09-07 Havoc Pennington * doc/dbus-specification.sgml: more updates 2003-09-06 Havoc Pennington * doc/dbus-specification.sgml: partial updates * bus/dbus-daemon-1.1.in: fix the config file docs for the zillionth time; hopefully I edited the right file this time. * bus/config-parser.c (append_rule_from_element): support send_type, send_path, receive_type, receive_path * bus/policy.c: add message type and path to the list of things that can be "firewalled" 2003-09-06 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_register_fallback): add this (dbus_connection_register_object_path): make this not handle messages to paths below the given path 2003-09-03 Havoc Pennington * test/glib/Makefile.am: add this with random glib-linked test programs * glib/Makefile.am: remove the random test programs from here, leave only the unit tests * glib/dbus-gobject.c (_dbus_gobject_test): add test for uscore/javacaps conversion, and fix (get_object_property, set_object_property): change to .NET convention for mapping props to methods, set_FooBar/get_FooBar, since one language has such a convention we may as well copy it. Plus real methods in either getFooBar or get_foo_bar style won't collide with this convention. 2003-09-01 Havoc Pennington * glib/dbus-gparser.c: implement * glib/dbus-gobject.c: start implementing skeletons support * configure.in: when disabling checks/assert, also define G_DISABLE_ASSERT and G_DISABLE_CHECKS 2003-09-01 Havoc Pennington * glib/Makefile.am: rearrange a bunch of files and get "make check" framework set up 2003-08-31 Havoc Pennington * fix build with --disable-tests 2003-08-30 Havoc Pennington * dbus/dbus-connection.c: purge DBusMessageHandler * dbus/dbus-message-handler.c: remove DBusMessageHandler, just use callbacks everywhere 2003-08-30 Havoc Pennington * test/data/valid-config-files/system.d/test.conf: change to root for the user so warnings don't get printed * dbus/dbus-message.c: add dbus_message_get_path, dbus_message_set_path * dbus/dbus-object-tree.c (do_test_dispatch): add test of dispatching to a path * dbus/dbus-string.c (_dbus_string_validate_path): add * dbus/dbus-marshal.c (_dbus_demarshal_object_path): implement (_dbus_marshal_object_path): implement * dbus/dbus-protocol.h (DBUS_HEADER_FIELD_PATH): new header field to contain the path to the target object (DBUS_HEADER_FIELD_SENDER_SERVICE): rename DBUS_HEADER_FIELD_SENDER to explicitly say it's the sender service 2003-08-30 Havoc Pennington * dbus/dbus-object-tree.c: write tests and fix the discovered bugs 2003-08-29 Havoc Pennington * dbus/dbus-object-tree.c: modify to allow overlapping paths to be registered (struct DBusObjectSubtree): shrink this a lot, since we may have a lot of them (_dbus_object_tree_free_all_unlocked): implement (_dbus_object_tree_dispatch_and_unlock): implement 2003-08-29 Havoc Pennington * dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS 2003-08-28 Havoc Pennington purge DBusObjectID * dbus/dbus-connection.c: port to no ObjectID, create a DBusObjectTree, rename ObjectTree to ObjectPath in public API * dbus/dbus-connection.h (struct DBusObjectTreeVTable): delete everything except UnregisterFunction and MessageFunction * dbus/dbus-marshal.c: port away from DBusObjectID, add DBUS_TYPE_OBJECT_PATH * dbus/dbus-object-registry.[hc], dbus/dbus-object.[hc], dbus/dbus-objectid.[hc]: remove these, we are moving to path-based object IDs 2003-08-25 Havoc Pennington Just noticed that dbus_message_test is hosed, I wonder when I broke that. I thought make check was passing earlier... * dbus/dbus-object-tree.c: add new "object tree" to match DCOP container tree, will replace most of dbus-object-registry * dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99 screwup 2003-08-19 Havoc Pennington * dbus/dbus-message.c (decode_string_field): support FIELD_SENDER (dbus_message_is_error): fix this function * bus/dbus-daemon-1.1: clarify logic on when / rules match * bus/policy.c (bus_client_policy_check_can_receive): fix code to reflect clarified man page (bus_client_policy_check_can_send): ditto * bus/session.conf.in: fixup * bus/system.conf.in: fixup 2003-08-18 Havoc Pennington * dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix dumb bug created earlier (wrong order of args to decode_header_data()) * tools/dbus-send.c: port * tools/dbus-print-message.c (print_message): port * test/data/*messages: port all messages over * dbus/dbus-message-builder.c: support including message type * bus/driver.c: port over * bus/dispatch.c: port over to new stuff * dbus/dbus-connection.c (_dbus_connection_new_for_transport): rename disconnect signal to "Disconnected" 2003-08-17 Havoc Pennington This doesn't compile yet, but syncing up so I can hack on it from work. What are branches for if not broken code? ;-) * dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER, DBUS_HEADER_FIELD_ERROR_NAME * dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use for the interface+member pairs (string_hash): change to use g_str_hash algorithm (find_direct_function, find_string_function): refactor these to share most code. * dbus/dbus-message.c: port all of this over to support interface/member fields instead of name field * dbus/dbus-object-registry.c: port over * dbus/dbus-string.c (_dbus_string_validate_interface): rename from _dbus_string_validate_name * bus/dbus-daemon-1.1: change file format for the / stuff to match new message naming scheme * bus/policy.c: port over * bus/config-parser.c: parse new format 2003-08-16 Havoc Pennington * dbus/dbus-object-registry.c (add_and_remove_objects): remove broken assertion * glib/dbus-gproxy.c: some hacking 2003-08-15 Havoc Pennington * dbus/dbus-pending-call.c (dbus_pending_call_block): implement * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): factor out internals; change to convert any error replies to DBusError instead of returning them as a message 2003-08-15 Havoc Pennington * dbus/dbus-connection.c, dbus/dbus-pending-call.c: Finish the pending call stuff 2003-08-14 Havoc Pennington * dbus/dbus-pending-call.c: start on new object that will replace DBusMessageHandler and ReplyHandlerData for tracking outstanding replies * dbus/dbus-gproxy.c: start on proxy object used to communicate with remote interfaces * dbus/dbus-gidl.c: do the boring boilerplate in here 2003-08-12 Havoc Pennington * bus/dispatch.c (bus_dispatch): make this return proper DBusHandlerResult to avoid DBUS_ERROR_UNKNOWN_METHOD * dbus/dbus-errors.c (dbus_set_error): use _dbus_string_append_printf_valist * dbus/dbus-string.c (_dbus_string_append_printf_valist) (_dbus_string_append_printf): new * dbus/dbus-errors.h (DBUS_ERROR_UNKNOWN_MESSAGE): change to UNKNOWN_METHOD * dbus/dbus-connection.c (dbus_connection_dispatch): handle DBUS_HANDLER_RESULT_NEED_MEMORY; send default error reply if a message is unhandled. 2003-08-11 Havoc Pennington * bus/test.c (client_disconnect_handler): change to return HANDLED (would have been REMOVE_MESSAGE) * dbus/dbus-object.h (enum DBusHandlerResult): rename to HANDLED/NOT_YET_HANDLED instead of REMOVE_MESSAGE/ALLOW_MORE_HANDLERS to make it clearer how it should be used. 2003-08-10 Havoc Pennington * tools/dbus-send.c (main): add --type argument, for now supporting only method_call and signal types. * tools/dbus-print-message.c: print message type * dbus/dbus-connection.c (_dbus_connection_new_for_transport): init connection->objects * doc/dbus-specification.sgml: fix sgml * bus/*.c: port over to object-instance API changes * test/test-service.c: ditto * dbus/dbus-message.c (dbus_message_create_header): allow #NULL name, we will have to fix up the rest of the code to also handle this (dbus_message_new): generic message-creation call (set_string_field): allow appending name field 2003-08-06 Havoc Pennington * dbus/dbus-object-registry.c: implement signal connection and dispatch * dbus/dbus-connection.c (_dbus_connection_unref_unlocked): new * dbus/dbus-internals.c (_dbus_memdup): new function 2003-08-02 Havoc Pennington * dbus/dbus-message.c (dbus_message_get_no_reply) (dbus_message_set_no_reply): add these and remove set_is_error/get_is_error * dbus/dbus-protocol.h, doc/dbus-specification.sgml: remove the ERROR flag, since there's now an ERROR type 2003-08-01 Havoc Pennington * dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock): implement * dbus/dbus-message.c (dbus_message_get_type): new function * doc/dbus-specification.sgml: add "type" byte to messages 2003-08-01 Havoc Pennington * dbus/dbus-protocol.h (DBUS_MESSAGE_TYPE_*): introduce a message type enum to distinguish kinds of message (DBUS_HEADER_FLAG_NO_REPLY_EXPECTED): flag for a message that need not be replied to 2003-08-01 Havoc Pennington * dbus/dbus-marshal.c: adapt to DBusObjectID changes (unpack_8_octets): fix no-64-bit-int bug * dbus/dbus-object-registry.c (validate_id): validate the connection ID bits, not just the instance ID. * dbus/dbus-connection.c (_dbus_connection_init_id): initialize the connection-global 33 bits of the object ID * dbus/dbus-object-registry.c (info_from_entry): fill in object ID in the new way * dbus/dbus-objectid.h: rather than high/low bits, specifically define server/client/instance bits. 2003-07-30 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_register_object): fix build 2003-07-13 Havoc Pennington * dbus/dbus-object.h (struct DBusObjectVTable): add padding fields to DBusObjectVTable and DBusObjectInfo 2003-07-12 Havoc Pennington * dbus/dbus-object-registry.c: implement unit test, fix bugs discovered in process * dbus/dbus-connection.c: remove handler_table and register_handler(), add DBusObjectRegistry usage * dbus/dbus-objectid.c (dbus_object_id_is_null) (dbus_object_id_set_null): new functions 2003-07-08 Havoc Pennington * dbus/dbus-object.c: implement some of this * dbus/dbus-object-registry.c (_dbus_object_registry_add_and_unlock): fill in the object_id out param (_dbus_object_registry_new): handle OOM 2003-07-08 Havoc Pennington * dbus/dbus-object.h: sketch out an API for registering objects with a connection, that allows us to use as little as 24 bytes per object and lets application code represent an object in any conceivable way. * dbus/dbus-object-registry.c: implement the hard bits of the DBusConnection aspect of object API. Not yet wired up. 2003-07-06 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_set_object_id): new function (_dbus_marshal_object_id): new (_dbus_demarshal_object_id): new (_dbus_marshal_get_arg_end_pos): support object ID type, and consolidate identical switch cases. Don't conditionalize handling of DBUS_TYPE_UINT64, need to handle the type always. (_dbus_marshal_validate_arg): consolidate identical cases, and handle DBUS_TYPE_OBJECT_ID * dbus/dbus-objectid.c: new file with DBusObjectID data type. * dbus/dbus-protocol.h: add DBUS_TYPE_OBJECT_ID 2003-09-28 Havoc Pennington * real 0.13 release 2003-09-28 Havoc Pennington * doc/Makefile.am (dbus-specification.html): testing a funky hack to work with Debian db2html 2003-09-28 Havoc Pennington * configure.in: 0.13 * doc/Makefile.am (dbus-test-plan.html): accept nonexistence of stylesheet-images for benefit of Debian Change back to using filesystem-linked sockets for the system bus, so only root can create the default system bus address. * bus/system.conf.in: change to use DBUS_SYSTEM_BUS_DEFAULT_ADDRESS * dbus/Makefile.am (INCLUDES): remove DBUS_SYSTEM_BUS_PATH define from here. * configure.in: define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS here, and AC_DEFINE DBUS_SYSTEM_PATH 2003-08-09 Anders Carlsson * doc/TODO: * doc/busconfig.dtd: Add busconfig DTD. 2003-08-09 Anders Carlsson * doc/dbus-specification.sgml: Add activation reply values. 2003-08-05 Havoc Pennington * configure.in: 0.12 2003-08-05 Anders Carlsson * glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref), (watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch), (add_watch), (remove_watch), (create_source): Refcount fds, fixes some reentrancy issues. 2003-07-30 Havoc Pennington * dbus/dbus-bus.c (init_connections_unlocked): fix default system bus address to be abstract if we have abstract sockets * NEWS: update 2003-07-28 Havoc Pennington * bus/messagebus.in: fix to avoid processname/servicename confusion, from Michael Kearey https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=100965 2003-07-23 Havoc Pennington * dbus/dbus-message.c (dbus_message_iter_get_named): fix from Andy Hanton to remove broken "+1" 2003-07-16 Havoc Pennington * tools/dbus-launch.c (babysit): close stdout/stderr in the babysitter process, as suggested by Thomas Leonard, so an "eval `dbus-launch --exit-with-session`" will actually return 2003-07-16 Havoc Pennington * configure.in: print out EXPANDED_* variables in the summary at the end; clean up the code that computes EXPANDED_ variables and get the ones using exec_prefix right. Should make things work when you build without --prefix 2003-06-29 Havoc Pennington * mono/Test.cs (class Test): fire up a main loop and run it * mono/DBus.cs (DBus): don't g_thread_init since it can only be done once, the app has to do it 2003-06-26 Havoc Pennington * mono/Connection.cs: set up connection with the glib main loop 2003-07-01 Havoc Pennington * doc/dbus-specification.sgml: clarify the format of a type code, change suggested by Jim Blandy 2003-06-29 Miloslav Trmac * doc/Makefile.am: * tools/Makefile.am: Don't assume srcdir == builddir. * dbus/dbus-memory.c (dbus_realloc): Don't check guards after shrinking the allocated block. (_dbus_memory_test): New function. * dbus/dbus-test.h: Add _dbus_memory_test (). * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): Call it. * dbus/dbus-message.c (decode_header_data): Use %.4s instead of %c%c%c%c. (dbus_message_new): Remove obsolete @todo. * dbus/dbus-marshal.c (_dbus_marshal_set_int64) (_dbus_marshal_set_uint64): Fix comment. * dbus/dbus-message.c (append_int_field, append_uint_field): Don't hardcode FIELD_REPLY_SERIAL. * dbus/dbus-mainloop.c (_dbus_loop_remove_watch) (_dbus_loop_remove_timeout): Cast function pointers to (void *) for %p * configure.in: Add -D_POSIX_C_SOURCE=199309L -DBSD_SOURCE to CFLAGS and disable DBUS_USE_ATOMIC_INT_486 when --enable-ansi is used 2003-06-24 Havoc Pennington * mono/*.cs: Use IntPtr.Zero instead of ((IntPtr) 0) 2003-06-23 Anders Carlsson * configure.in: * gcj/.cvsignore: * gcj/Hello.java: * gcj/Makefile.am: * gcj/TestMessage.java: (TestMessage), (TestMessage.main): * gcj/org/.cvsignore: * gcj/org/Makefile.am: * gcj/org/freedesktop/.cvsignore: * gcj/org/freedesktop/Makefile.am: * gcj/org/freedesktop/dbus/.cvsignore: * gcj/org/freedesktop/dbus/Makefile.am: * gcj/org/freedesktop/dbus/Message.java: (Message), (Message.Message): * gcj/org/freedesktop/dbus/natMessage.cc: Fix the build system. 2003-06-22 Havoc Pennington * mono/Connection.cs: add more bindings * dbus/dbus-threads.c (dbus_threads_init): allow calling this more than once. 2003-06-22 Havoc Pennington * mono/Connection.cs, mono/DBus.cs, mono/Error.cs: Start wrapping more stuff. 2003-06-22 Havoc Pennington * mono/Message.cs: implement Message.Wrap() that ensures we only have a single C# wrapper per DBusMessage, assuming it works which it probably doesn't. * dbus/dbus-message.c (dbus_message_allocate_data_slot): new (dbus_message_free_data_slot): new (dbus_message_set_data): new (dbus_message_get_data): new 2003-06-22 Havoc Pennington * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref) (_dbus_data_slot_allocator_alloc): rework these to keep a reference count on each slot and automatically manage a global slot ID variable passed in by address * bus/bus.c: convert to new dataslot API * dbus/dbus-bus.c: convert to new dataslot API * dbus/dbus-connection.c: convert to new dataslot API * dbus/dbus-server.c: convert to new dataslot API * glib/dbus-gmain.c: ditto * bus/test.c: ditto * bus/connection.c: ditto 2003-06-22 Anders Carlsson * configure.in: Add AM_PROG_GCJ and move AM_PROG_LIBTOOL after the gcj checks so that the correct configuration tags will be added to libtool. * dbus-glib-1.pc.in: No need to specify any includes since dbus-1.pc.in has those. 2003-06-22 Havoc Pennington * mono/*, gcj/*, configure.in, Makefile.am: Check in makefiles and subdirs for mono and gcj bindings. Neither binding actually exists, just trying to get through all the build and other boring bits. 2003-06-21 Philip Blundell * tools/dbus-monitor.1: Updated. * tools/dbus-send.1: Likewise. 2003-06-20 Anders Carlsson * dbus/dbus-transport-unix.c (unix_handle_watch): Check for hangup and error after checking read so we won't discard pending data if both hangup and read are set. 2003-06-19 Philip Blundell * tools/dbus-print-message.c (print_message): Handle BOOLEAN. * tools/dbus-send.c: Accept both --system and --session. * tools/dbus-monitor.c: Same here. 2003-06-19 Anders Carlsson * glib/dbus-glib.h: Fix so that dbus-glib.h can be used from C++ (Patch by Miloslav Trmac). 2003-06-15 Joe Shaw * configure.in: Check for socklen_t. * dbus/dbus-sysdeps.c: Define socklen_t if it's not defined. * test/test-segfault.c: Add #include * tools/Makefile.am: Add DBUS_X_CFLAGS to the INCLUDES since dbus-launch needs it. 2003-06-09 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): don't use SUN_LEN, it breaks abstract socket usage * dbus/dbus-internals.c (_dbus_verbose_real): only print PID at starts of lines. 2003-06-04 Havoc Pennington * dbus/dbus-server.c (dbus_server_listen): allow abstract sockets using unix:abstract=/foo, and when listening in a tmpdir i.e. unix:tmpdir=/tmp, always use abstract sockets if we can. * dbus/dbus-transport.c (_dbus_transport_open): support unix:abstract=/foo * dbus/dbus-server-unix.c (_dbus_server_new_for_domain_socket): support abstract sockets * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket): support abstract sockets * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket): add "abstract" toggle as an argument, implement abstract namespace support (_dbus_listen_unix_socket): ditto * configure.in: add --enable-abstract-sockets and implement a configure check for autodetection of the right value. 2003-06-01 Havoc Pennington * tools/dbus-cleanup-sockets.c: add utility to clean up sockets in /tmp (though on Linux this will end up being useless, when we add abstract namespace support) * configure.in: define DBUS_SESSION_SOCKET_DIR in addition to subst'ing it 2003-05-28 Colin Walters * tools/dbus-monitor.c (main): Fix silly typo (s/--session/--system/). 2003-05-18 Anders Carlsson * dbus/dbus-message.c (dbus_message_new): Remove @todo. 2003-05-17 Colin Walters * tools/dbus-send.c: Don't exit with an error code if --help was passed. Default to using the session bus instead of the system one. * tools/dbus-launch.c: Ditto. * tools/dbus-monitor.c: Ditto. * tools/dbus-send.1: Update with new arguments. * tools/dbus-launch.c: Emit code to export variables. New arguments -s and -c to specify shell syntax, and a bit of code to autodetect syntax. Also, allow specifying a program to run. * tools/dbus-launch.1: Update with new arguments. * tools/dbus-send.1: Ditto. * tools/dbus-monitor.1: Ditto. 2003-05-17 Havoc Pennington * bus/config-parser.c (merge_included): merge in policies from child configuration file. * bus/policy.c (bus_policy_merge): function to merge two policies together 2003-05-16 Havoc Pennington * dbus/dbus-connection.c: disable verbose lock spew * tools/dbus-send.c: add --print-reply command line option * tools/dbus-print-message.h (print_message): new util function shared by dbus-send and dbus-monitor * tools/dbus-monitor.c (handler_func): exit on disconnect * dbus/dbus-transport-unix.c (do_reading): if the transport is disconnected, don't try to use the read_watch * dbus/dbus-watch.c (dbus_watch_get_enabled): assert watch != NULL so we can find this bug more easily 2003-05-16 Havoc Pennington * bus/policy.c (free_rule_list_func): avoid a crash when passed NULL as DBusHashTable is annoyingly likely to do. 2003-05-16 Colin Walters * tools/dbus-monitor.c: Add --session argument and usage() function. * tools/dbus-monitor.1: Update with new --session arg. * bus/Makefile.am (install-data-hook): Create $(libdir)/dbus-1.0/services so that the session bus is happy. 2003-05-15 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_atomic_dec, _dbus_atomic_inc): work on non-x86. ifdef's are evil. 2003-05-15 Havoc Pennington * configure.in: 0.11 * NEWS: update * bus/Makefile.am (initddir): apparently we are supposed to put init scripts in /etc/rc.d/init.d not /etc/init.d * bus/Makefile.am: remove the "you must --enable-tests to make check" as it broke distcheck * bus/Makefile.am (install-data-hook): create /etc/dbus-1/system.d 2003-05-13 James Willcox * configure.in: * bus/activation.c: (bus_activation_service_created), (bus_activation_activate_service): * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_send_service_lost), (bus_driver_send_service_acquired), (bus_driver_send_welcome_message), (bus_driver_handle_list_services): * bus/session.conf.in: * dbus/dbus-bus.c: (dbus_bus_acquire_service), (dbus_bus_service_exists), (dbus_bus_activate_service): * dbus/dbus-bus.h: Add some convenience API which lets you activate a service, and did a bunch of s/0/DBUS_TYPE_INVALID/ in calls to dbus_message_append_args() and dbus_message_get_args() 2003-05-11 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid calling _dbus_marshal_validate_arg() for every byte in a byte array, etc. * dbus/dbus-message-handler.c: use atomic reference counting to reduce number of locks slightly; the global lock in here sucks * dbus/dbus-connection.c (_dbus_connection_update_dispatch_status_and_unlock): variant of update_dispatch_status that can be called with lock held; then use in a couple places to reduce locking/unlocking (dbus_connection_send): hold the lock over the whole function instead of acquiring it twice. * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM * bus/connection.c (bus_connections_setup_connection): fix access to already-freed memory. * dbus/dbus-connection.c: keep a little cache of linked list nodes, to avoid using the global linked list alloc lock in the normal send-message case. Instead we just use the connection lock that we already have to take. * dbus/dbus-list.c (_dbus_list_find_last): new function * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): change to use a struct for the atomic type; fix docs, they return value before increment, not after increment. * dbus/dbus-string.c (_dbus_string_append_4_aligned) (_dbus_string_append_8_aligned): new functions to try to microoptimize this operation. (reallocate_for_length): break this out of set_length(), to improve profile info, and also so we can consider inlining the set_length() part. * dbus/dbus-message.c (dbus_message_new_empty_header): init data strings with some preallocation, cuts down on our calls to realloc a fair bit. Though if we can get the "move entire string to empty string" optimization below to kick in here, it would be better. * dbus/dbus-string.c (_dbus_string_move): just call _dbus_string_move_len (_dbus_string_move_len): add a special case for moving an entire string into an empty string; we can just swap the string data instead of doing any reallocs. (_dbus_string_init_preallocated): new function 2003-05-11 Havoc Pennington Write a "test-profile" that does echo client-server with threads; profile reveals lock contention, memcpy/realloc of buffers, and UTF-8 validation as hot spots. 20% of lock contention eliminated with dbus_atomic_inc/dec implementation on x86. Much remaining contention is global mempool locks for GList and DBusList. * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add x86 implementation * dbus/dbus-connection.c (struct DBusConnection): use dbus_atomic_t for the reference count * dbus/dbus-message.c (struct DBusMessage): declare dbus_atomic_t values as volatile * configure.in: code to detect ability to use atomic integer operations in assembly, from GLib patch * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every time, tired of it being wrong in threads and forked processes * glib/test-profile.c: a little program to bounce messages back and forth between threads and eat CPU * dbus/dbus-connection.c: add debug spew macros for debugging thread locks; include config.h at top; fix deadlock in dbus_connection_flush() 2003-05-08 Havoc Pennington * dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov data from getting written, and there wasn't a good reason to use _exit really. * test/decode-gcov.c (mark_inside_dbus_build_tests): don't count dbus_verbose lines in test coverage (main): add list of functions sorted by # of untested blocks to the coverage report * dbus/dbus-mempool.c: put some test-only code in DBUS_BUILD_TESTS * dbus/dbus-marshal.c (_dbus_marshal_test): extend test coverage * dbus/dbus-message-handler.c (_dbus_message_handler_test): extend test coverage * test/data/auth/cancel.auth-script: test canceling an authentication * dbus/Makefile.am: remove dbus-server-debug.[hc] for now, as they aren't used. in CVS history if we end up needing them. 2003-05-04 Havoc Pennington * dbus/dbus-message-handler.c (_dbus_message_handler_test): add unit test * dbus/dbus-marshal.c (_dbus_demarshal_string_array): fix this function, which assumed length was in # of strings, not bytes * dbus/dbus-message.c (_dbus_message_test): add tests for some missing coverage * dbus/dbus-connection.c (_dbus_connection_queue_received_message): disable function for now, we are only using it in test mode * dbus/dbus-message.c (_dbus_message_loader_queue_messages): remove a mistaken FIXME 2003-05-04 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_preallocate_send): unlock mutex on successful return, patch from Anders Gustafsson 2003-05-04 Havoc Pennington * dbus-glib-1.pc.in (Requires): fix dependencies, from Anders Gustafsson 2003-05-04 Havoc Pennington * tools/dbus-launch.c: implement * bus/main.c (main), bus/bus.c (bus_context_new): implement --print-pid and --fork 2003-05-03 Havoc Pennington * dbus/dbus-address.c (dbus_parse_address): fix bug when a key in the address had no value, and add to test suite. Fix and regression test from Miloslav Trmac 2003-05-03 Havoc Pennington * dbus/dbus-watch.c (dbus_watch_handle): warn and return if a watch is invalid when handled * tools/Makefile.am, tools/dbus-launch.c, tools/dbus-launch.1: add dbus-launch utility to launch the bus from a shell script. Didn't actually implement dbus-launch yet, it's just a placeholder still. 2003-05-03 Havoc Pennington * bus/Makefile.am, bus/dbus-daemon-1.1.in: man page for the daemon; also documents daemon config file, so replaces doc/config-file.txt. Corrected some stuff from config-file.txt in the process of moving it. 2003-05-03 Havoc Pennington * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1: add some man pages 2003-05-03 Colin Walters * dbus/dbus-sysdeps.c (fill_user_info): Test against DBUS_UID_UNSET to determine whether to do a uid lookup or not. * Makefile.am: Update to use new .pc versioning scheme. 2003-05-02 Havoc Pennington * bus/system.conf.in: allow send/receive to/from message bus service 2003-04-30 Havoc Pennington * configure.in: print a note when building with unit tests and without assertions 2003-04-30 Havoc Pennington * Makefile.am: add a check-local that complains if you didn't configure with --enable-tests 2003-04-29 Havoc Pennington * glib/dbus-gmain.c: docs cleanups * dbus/dbus-types.h: add docs on int64 types * dbus/dbus-memory.c: fix docs to avoid putting private API in public API docs section 2003-04-29 Havoc Pennington * dbus-1.pc.in, dbus-glib-1.pc.in: rename these from dbus-1.0.pc.in, dbus-glib-1.0.pc.in. As these change with the parallel install API version, not with the D-BUS package version. * HACKING: move some of README over here * README: updates, and document API/ABI policy * configure.in: reindentation 2003-04-29 Havoc Pennington * dbus/dbus.h: add "you have to define DBUS_API_SUBJECT_TO_CHANGE to use this library" to be sure people have the right expectations. 2003-04-28 Havoc Pennington * configure.in: add --enable-docs which by default is auto yes if doxygen and db2html found, no otherwise; but can be forced on/off * doc/Makefile.am: conditionalize whether to build docs on --enable-docs 2003-04-28 Havoc Pennington * configure.in: 0.10 * NEWS: update * bus/system.conf.in: add system.d * dbus/dbus-userdb.c (_dbus_user_database_lookup): fix bug when username was provided but not uid * bus/config-parser.c (struct BusConfigParser): keep track of whether the parser is toplevel or was included; change some of the error handling if it's included. 2003-04-27 Havoc Pennington Unbreak my code... * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): report correct status if we finish processing authentication inside this function. * bus/activation.c (try_send_activation_failure): use bus_transaction_send_error_reply * bus/connection.c (bus_connection_get_groups): return an error explaining the problem * bus/bus.c (bus_context_check_security_policy): implement restriction here that inactive connections can only send the hello message. Also, allow bus driver to send anything to any recipient. * bus/connection.c (bus_connection_complete): create the BusClientPolicy here instead of on-demand. (bus_connection_get_policy): don't return an error * dbus/dbus-message.c (dbus_message_new_error_reply): allow NULL sender field in message being replied to * bus/bus.c (bus_context_check_security_policy): fix silly typo causing it to return FALSE always * bus/policy.c (bus_client_policy_check_can_send): fix bug where we checked sender rather than destination 2003-04-25 Havoc Pennington test suite is slightly hosed at the moment, will fix soon * bus/connection.c (bus_connections_expire_incomplete): fix to properly disable the timeout when required (bus_connection_set_name): check whether we can remove incomplete connections timeout after we complete each connection. * dbus/dbus-mainloop.c (check_timeout): fix this up a bit, probably still broken. * bus/services.c (bus_registry_acquire_service): implement max number of services owned, and honor allow/deny rules on which services a connection can own. * bus/connection.c (bus_connection_get_policy): report errors here * bus/activation.c: implement limit on number of pending activations 2003-04-25 Havoc Pennington * dbus/dbus-transport.c (_dbus_transport_get_unix_user): fix bug where we used >= 0 instead of != DBUS_UID_UNSET. 2003-04-25 Havoc Pennington * glib/dbus-gmain.c (remove_watch): fix for a crash when watches were toggled without add/remove, fix from Anders Gustafsson 2003-04-24 Havoc Pennington * test/data/valid-config-files/basic.conf: add tags to this test * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement tag in configuration file. 2003-04-24 Havoc Pennington * bus/dispatch.c: somehow missed some name_is * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) (_dbus_timeout_set_interval): new * bus/connection.c (bus_connections_setup_connection): record time when each connection is first set up, and expire them after the auth timeout passes. 2003-04-24 Havoc Pennington * dbus/dbus-message.c (dbus_message_name_is): rename (dbus_message_service_is): rename (dbus_message_sender_is): rename (dbus_message_get_service): rename 2003-04-24 Havoc Pennington * configure.in: add --enable-checks * dbus/dbus-message.c (dbus_message_new): reverse name/service arguments * dbus/dbus-connection.c (dbus_connection_preallocate_send): fix to use thread locks. (_dbus_connection_handler_destroyed_locked): move some private functions into proper docs group * dbus/dbus-internals.h: add _dbus_return_if_fail, _dbus_return_val_if_fail Throughout: use dbus_return_if_fail 2003-04-23 James Willcox * glib/dbus-glib.h: * glib/dbus-gmain.c: (add_timeout), (wakeup_main), (create_source), (dbus_connection_setup_with_g_main), (dbus_server_setup_with_g_main): * glib/test-dbus-glib.c: (main): * glib/test-thread-client.c: (main): * glib/test-thread-server.c: (new_connection_callback), (main): * tools/dbus-monitor.c: (main): Added a GMainContext argument to dbus_connection_setup_with_g_main() and dbus_server_setup_with_g_main(). 2003-04-20 Havoc Pennington * doc/dbus-specification.sgml: document the restrictions on message and service names 2003-04-22 Havoc Pennington * dbus/dbus-message.c, dbus/dbus-marshal.c: add 64-bit integer support, and do some code cleanups to share more code and speed up array marshal/demarshal. * dbus-1.0.pc.in (Cflags): put libdir include file in cflags * configure.in: generate dbus-arch-deps.h * dbus/dbus-protocol.h (DBUS_TYPE_INT64, DBUS_TYPE_UINT64): add 64-bit typecodes 2003-04-22 Havoc Pennington * test/data/valid-messages/opposite-endian.message: fix test to use proper type for rply field * test/data/invalid-messages: add tests for below validation * dbus/dbus-message.c (decode_header_data): validate field types, and validate that named fields are valid names (decode_name_field): consider messages in the org.freedesktop.Local. namespace to be invalid. * dbus/dbus-string.c (_dbus_string_validate_name): new 2003-04-19 Havoc Pennington * bus/driver.c (bus_driver_handle_hello): check limits and return an error if they are exceeded. * bus/connection.c: maintain separate lists of active and inactive connections, and a count of each. Maintain count of completed connections per user. Implement code to check connection limits. * dbus/dbus-list.c (_dbus_list_unlink): export * bus/bus.c (bus_context_check_security_policy): enforce a maximum number of bytes in the message queue for a connection 2003-04-18 Havoc Pennington * dbus/dbus-auth.c (record_mechanisms): memleak fixes * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): fix some memleaks * dbus/dbus-keyring.c (add_new_key): fix a memleak, and on realloc be sure to update the pointer in the keyring * dbus/dbus-string.c (_dbus_string_zero): compensate for align offset to avoid writing to unallocated memory * dbus/dbus-auth.c (process_rejected): return FALSE if we fail to try the next mechanism, so we properly handle OOM * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): fix double-free on OOM. (_dbus_keyring_new): fix OOM bug (_dbus_keyring_new_homedir): always set error; impose a maximum number of keys we'll load from the file, mostly to speed up the test suite and make its OOM checks more useful, but also for general sanity. * dbus/dbus-auth.c (process_error_server): reject authentication if we get an error from the client (process_cancel): on cancel, send REJECTED, per the spec (process_error_client): send CANCEL if we get an error from the server. 2003-04-18 Havoc Pennington * dbus/dbus-mainloop.c (_dbus_loop_iterate): fix UMR in verbose debug spew * dbus/dbus-auth.c (handle_client_data_cookie_sha1_mech): fix OOM handling problem * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): only whine about DBUS_TEST_HOMEDIR once * bus/Makefile.am (TESTS_ENVIRONMENT): put DBUS_TEST_HOMEDIR in the environment * bus/dispatch.c (bus_dispatch_sha1_test): actually load sha1 config file so we test the right thing Throughout: assorted docs improvements 2003-04-18 Havoc Pennington * glib/dbus-gmain.c: adapt to watch changes * bus/bus.c, bus/activation.c, etc.: adjust to watch changes * dbus/dbus-server.h: remove dbus_server_handle_watch * dbus/dbus-connection.h: remove dbus_connection_handle_watch * dbus/dbus-watch.c (dbus_watch_handle): change DBusWatch to work like DBusTimeout, so we don't need dbus_connection_handle_watch etc. 2003-04-17 Havoc Pennington * dbus/dbus-userdb.c, dbus/dbus-sysdeps.c: redo all the passwd database usage so it all goes via the DBusUserDatabase cache. 2003-04-17 Havoc Pennington * dbus/dbus-mainloop.c (_dbus_loop_iterate): fix logic so that if there was an OOM watch we skipped, we always return TRUE so we iterate again to have a look at it again. Fixes test suite hang. Code rearrangement also lets us lose some memset and only iterate over callbacks once. * bus/driver.c (bus_driver_handle_message): sense of test for reply was backward 2003-04-16 Havoc Pennington * doc/dbus-specification.sgml: make spec say serials are unsigned * dbus/dbus-message.h: change message serials to unsigned * dbus/dbus-connection.c: adapt to message serials being unsigned 2003-04-15 Havoc Pennington * bus/bus.c: create and keep around a shared DBusUserDatabase object. * bus/connection.c (bus_connection_get_groups): don't cache groups for user in the connection object, since user database object now does that. 2003-04-16 Havoc Pennington * dbus/dbus-message.c (_dbus_message_add_size_counter): keep a list of size counters (_dbus_message_loader_putback_message_link): put back a popped link * dbus/dbus-connection.c (dbus_connection_set_max_live_messages_size): rename max_received_size (dbus_connection_get_outgoing_size): get size of outgoing queue (_dbus_connection_set_connection_counter): remove this cruft 2003-04-14 Havoc Pennington * dbus/dbus-userdb.c: user database abstraction, mostly to get caching, but at some point we might want to be able to use a different database. * bus/dispatch.c (bus_dispatch_sha1_test): add a test that uses SHA1 conf file to test the sha1 auth mechanism, since the regular test always uses EXTERNAL when available. * configure.in, test/data/valid-config-files/debug-allow-all-sha1.conf.in: add conf file that requires use of sha1 auth 2003-04-13 Havoc Pennington * tools/dbus-send.c, tools/dbus-monitor.c: two utility programs from Philip Blundell to send messages and monitor them. 2003-04-13 Havoc Pennington * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting callbacks * test/data/valid-config-files/debug-allow-all.conf.in: allow all users * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): fix to only recover unused bytes if we're already authenticated (_dbus_transport_get_is_authenticated): fix to still mark us authenticated if there are unused bytes. * bus/dispatch.c: implement security policy checking * bus/connection.c (bus_transaction_send_from_driver): new * bus/bus.c (bus_context_check_security_policy): new * bus/dispatch.c (send_service_nonexistent_error): delete this, now we just set the DBusError and it gets converted to an error reply. * bus/connection.c (allow_user_function): enable code using actual data from the config file * bus/policy.c (list_allows_user): handle wildcard rules for user/group connection perms 2003-04-13 Havoc Pennington * bus/config-parser.c: Load up the BusPolicy and BusPolicyRules * dbus/dbus-sysdeps.c (_dbus_get_user_id): new function * bus/policy.c (bus_policy_append_mandatory_rule) (bus_policy_append_default_rule, bus_policy_append_user_rule) (bus_policy_append_group_rule): new functions 2003-04-12 Havoc Pennington * bus/config-parser.c (bus_config_parser_new): fix a memleak * dbus/dbus-sysdeps.c: change DBusCredentials to use longs for the pid/gid/uid, just for paranoia. * test/break-loader.c (randomly_do_n_things): find a byte containing a type code, and randomly change it to a different type code. 2003-04-12 Havoc Pennington * bus/policy.h: change BusPolicy to be the thing from the config file, and rename old BusPolicy to BusClientPolicy * bus/bus.c, bus/connection.c, bus/config-parser.c: change to match change in how policy works * dbus/dbus-internals.h: mark assert_not_reached as __attribute((noreturn))__ 2003-04-11 Havoc Pennington * doc/dbus-specification.sgml: fix a spot with the wrong name for the broadcast service. Use boolean return for ServiceExists. 2003-04-11 Havoc Pennington * configure.in: add another directory to look for qt in. 2003-04-11 Havoc Pennington * AUTHORS: add Colin Walters 2003-04-11 Havoc Pennington * NEWS: update * configure.in: 0.9 2003-04-11 Havoc Pennington * bus/messagebus.in: remove pid file when stopping the message bus, since the bus won't have privileges to remove it itself. 2003-04-11 Havoc Pennington * bus/bus.c (bus_context_new): move credentials change after creating pidfile 2003-04-11 Havoc Pennington * test/decode-gcov.c: add "below average functions" to the coverage report, and change how some of the code works. * bus/test-main.c: bracket some stuff in DBUS_BUILD_TESTS so it's not in the coverage stats. * test/test-service.c (main): use _dbus_verbose not fprintf in a couple places so running the test suite doesn't result in megaspam. 2003-04-11 Havoc Pennington * bus/dispatch.c (check_existent_service_activation): accept a no memory error in a place we didn't before * bus/test.c (bus_test_run_everything): remove hacky "do it twice in case the first one failed," since the test suite is less broken now. 2003-04-10 Havoc Pennington * bus/dispatch.c (check_segfault_service_activation): add test for launching an executable that just crashes. * test/test-segfault.c (main): try setting coredumpsize to 0 so we don't leave a million cores. We'll see how portable this is. 2003-04-10 Havoc Pennington * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): move all the possible parent failures before we fork, so that we don't fail to create a babysitter after creating the child. * bus/activation.c (bus_activation_activate_service): kill child if we don't successfully complete the activation. 2003-04-10 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_flush): don't spin on the connection if it's disconnected * bus/activation.c (bus_activation_service_created): use new transaction features to roll back removal of pending activation if we don't successfully create the service after all. Don't remove pending activation if the function fails. * dbus/dbus-list.c (_dbus_list_insert_before_link) (_dbus_list_insert_after_link): new code to facilitate services.c fixes * dbus/dbus-hash.c (_dbus_hash_table_insert_string_preallocated): new functionality, so we can preallocate the ability to insert into a hash table. * bus/connection.c (bus_transaction_add_cancel_hook): new function allowing us to put custom hooks in a transaction to be used for cancelling said transaction * doc/dbus-specification.sgml: add some discussion of secondary service owners, and disallow zero-length service names * bus/services.c (bus_registry_acquire_service): new function, splits out part of bus_driver_handle_acquire_service() and fixes a bug where we didn't remove the service doing the acquiring from the secondary queue if we failed to remove the current owner from the front of the queue. 2003-04-10 Alexander Larsson * doc/dbus-specification.sgml: s/org.freedesktop.Broadcast/org.freedesktop.DBus.Broadcast/ 2003-04-10 Alexander Larsson * bus/.cvsignore: * glib/.cvsignore: * test/.cvsignore: Added files to cvsignore * dbus/dbus-message.h: * dbus/dbus-message.c: (dbus_message_iter_get_named): Make get_named() take two out argument and return a boolean. (dbus_message_iter_get_args_valist): Update usage of get_named(). (dbus_message_iter_append_byte): Fix typo (dbus_message_iter_append_named) Fix typo (message_iter_test), (check_message_handling_type), (_dbus_message_test): More tests. 2003-04-10 Alexander Larsson * dbus/dbus-marshal.[ch]: Add array_type_pos argument to _dbus_marshal_validate_arg. Let you pass a NULL end_pos to _dbus_marshal_validate_type. * dbus/dbus-message.[ch]: Multi-dimensional arrays have full type specification in the outermost array. Iter code re-arranged to handle this. Added some more iter tests. * doc/dbus-specification.sgml: Add me to authors. Remove old FIXME. Update new array encoding description. Correct DBUS_SERVICE_FLAGS_REPLACE_EXISTING description. * test/data/invalid-messages/array-with-mixed-types.message: * test/data/valid-messages/array-of-array-of-uint32.message: Change to the new array format. * test/data/invalid-messages/too-short-dict.message: Fix bug in test. * test/data/valid-messages/recursive-types.message: Fix up and extend test. 2003-04-10 Havoc Pennington * bus/dispatch.c: lots of fixes * dbus/dbus-mainloop.c (_dbus_loop_dispatch): export (_dbus_loop_iterate): remove old "quit if no callbacks" code, that was crack, broke the test service. * dbus/dbus-transport.c (_dbus_transport_open): fix error handling to avoid piling up errors if we get a failure on the first address. * dbus/dbus-internals.c (_dbus_real_assert_not_reached): include pid in assertion failures. * dbus/dbus-mainloop.c (_dbus_loop_iterate): use static arrays up to some fixed size of file descriptor array. Don't return TRUE anytime a timeout exists, that led to lots of busy loop silliness in the tests. 2003-04-09 Havoc Pennington * dbus/dbus-mainloop.c (check_timeout): fix timeouts, I thought I'd checked this in earlier but hadn't. 2003-04-09 Havoc Pennington * bus/dispatch.c (bus_dispatch_test): get a bit further through the activation test (man this is getting old!) 2003-04-09 Havoc Pennington * test/test-utils.c: use dispatch status function to fix this up * bus/connection.c (connection_watch_callback): don't dispatch from here (connection_timeout_callback): don't dispatch from here (bus_connections_setup_connection): set the dispatch status function (bus_connection_disconnected): unset it * dbus/dbus-mainloop.c (_dbus_loop_queue_dispatch): new function used to add a connection to be dispatched (_dbus_loop_iterate): do the dispatching at the end of each iteration * dbus/dbus-connection.c (dbus_connection_set_dispatch_status_function): new function allowing us to fix up main loop usage (_dbus_connection_last_unref): free all the various function user data (dbus_connection_dispatch): call the DispatchStatusFunction whenever this function returns (dbus_connection_handle_watch): call DispatchStatusFunction (dbus_connection_send_with_reply_and_block): call DispatchStatusFunction (reply_handler_timeout): call DispatchStatusFunction (dbus_connection_flush): call DispatchStatusFunction 2003-04-09 Havoc Pennington * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and a memory leak * bus/dispatch.c (check_service_activated): fix bug in test * dbus/dbus-mainloop.c (check_timeout): fix this up * dbus/dbus-internals.c (_dbus_verbose_real): include PID in verbose output so we can sort out output from different processes, e.g. in the activation case. 2003-04-08 Colin Walters * bus/bus.c (struct BusContext) [pidfile]: New member, to store the pid file. (bus_context_new): Set it. (bus_context_unref): Use it to delete the pid file. 2003-04-08 Havoc Pennington * test/data/invalid-messages/array-with-mixed-types.message: regression test that fails for the moment * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): reorder tests for convenience * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): don't allow array of nil, it broke things. * test/data/invalid-messages/array-of-nil.message: regression test * test/data/valid-messages/array-of-array-of-uint32.message: happened to write this so added it to suite 2003-04-08 Havoc Pennington * bus/driver.c (bus_driver_handle_acquire_service): init retval/reply before checking name * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add a recursion depth argument * dbus/dbus-message.h (struct DBusMessageIter): put some padding in the public struct for future extension * dbus/dbus-message-builder.c (_dbus_message_data_load): fix typo * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix a verbose message * doc/dbus-specification.sgml: fix typo 2003-04-08 Alexander Larsson Implemented recursive types, named types and new-style iters * bus/driver.c: * glib/test-thread-client.c: (thread_func): * glib/test-thread-server.c: (handle_test_message): * test/test-service.c: (handle_echo): Update to new api * dbus/Makefile.am: * dbus/dbus-dict.c: * dbus/dbus-dict.h: * dbus/dbus.h Remove DBusDict * dbus/dbus-internals.c: (_dbus_type_to_string): Update for new types. * dbus/dbus-marshal.[ch]: Implement recursive types and the new marshalling format. Remove hardcoded dict marshalling. Marshal named types. * dbus/dbus-message-builder.c: Add BYTE_ARRAY. Remove references to old types * dbus/dbus-message.[ch]: New non-refcounted iter API that supports recursive iters. Use iters for appending, including support for recursive iters. Add byte and named type support. Update everything to new marshalling formats. Add tests for new API. * dbus/dbus-protocol.h: Remove old array types. Add types: BYTE, ARRAY, DICT, NAMED * dbus/dbus-string.c: * dbus/dbus-sysdeps.c: Make parse_double locale safe. * dbus/dbus-test-main.c: Call setlocale. * dbus/dbus-test.c: Kill dict test * doc/dbus-specification.sgml: Update spec * test/data/incomplete-messages/missing-body.message: * test/data/invalid-messages/bad-boolean.message: * test/data/invalid-messages/bad-boolean-array.message: * test/data/invalid-messages/boolean-array-length-too-long.message-raw: * test/data/invalid-messages/boolean-has-no-value.message-raw: * test/data/invalid-messages/too-short-dict.message: * test/data/valid-messages/dict-simple.message: * test/data/valid-messages/dict.message: * test/data/valid-messages/emptiness.message: * test/data/valid-messages/lots-of-arguments.message: * test/data/valid-messages/no-padding.message: * test/data/valid-messages/recursive-types.message: Add missing NAME fields Fix up dicts & arrays * test/data/invalid-messages/dict-with-nil-value.message: Removed, this is not invalid anymore. * test/data/valid-messages/recursive-types.message: Add new test for deeply recursive types. 2003-04-07 Havoc Pennington * bus/driver.c (bus_driver_handle_acquire_service): return an error if you try to acquire a service that starts with ':' 2003-04-07 Havoc Pennington * doc/dbus-specification.sgml: require that base service names start with ':' and that the base service is created/deleted as first and last things a connection does on the bus * bus/dispatch.c (check_existent_service_activation): lots more work on the activation test; it doesn't fully pass yet... * test/test-service.c (main): fix so we don't memleak the connection to the message bus (filter_func): accept a message asking us to exit 2003-04-06 Havoc Pennington * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h, from Colin Walters * configure.in: fixes to Qt detection from Colin Walters * doc/Makefile.am: Only remove generated docbook dirs if they exist, from Colin Walters * dbus/dbus-bus.c: change how we set well-known connections to NULL, so that it works if a single connection is stored in two well-known array slots. * test/Makefile.am: remove a lot of stuff that isn't immediately useful, it's in CVS history if we want it. * test/test-service.c: use dbus-mainloop instead of that watch.[hc] crack 2003-04-06 Havoc Pennington * dbus/Makefile.am: split lists of sources into stuff that goes in the library, util functions that go in the lib and are also used elsewhere, and util functions that are used in tests/daemon but don't go in the lib. * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc] here so it can be used in test binaries also 2003-04-06 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_become_daemon): write the pidfile here in the parent process, so we can return an error if it fails. Also, move some of the code into the child so the parent is less hosed if we fail midway through. * bus/bus.c (bus_context_new): move pidfile detection further up in the function, before we start overwriting sockets and such. * bus/messagebus.in: adjust this a bit, not sure if it will work. * configure.in: add --with-system-pid-file and --with-system-socket 2003-04-06 Colin Walters * configure.in (DBUS_SYSTEM_PID_FILE): New variable. * bus/system.conf.in: Declare a pidfile. * bus/bus.c (bus_context_new): Test for an existing pid file, and create one (if appropriate). * bus/config-parser.c (enum ElementType) [ELEMENT_PIDFILE]: New. (struct BusConfigParser) [pidfile]: New. (element_type_to_name, merge_included, start_busconfig_child) (bus_config_parser_end_element, bus_config_parser_content): Handle it. (bus_config_parser_unref): Free it. (bus_config_parser_get_pidfile): New function. * bus/config-parser.h (_dbus_write_pid_file): Prototype. * dbus/dbus-errors.h (DBUS_ERROR_PIDFILE_EXISTS): New error. * dbus/dbus-sysdeps.c (_dbus_write_pid_file): New function. * dbus/dbus-sysdeps.h: Prototype it. 2003-04-06 Havoc Pennington * bus/bus.c (bus_context_new): print the address in here, rather than in main(), because we need to do it before forking the daemon * bus/dispatch.c (send_service_nonexistent_error): set the sender on the service nonexistent error * bus/driver.c (bus_driver_handle_acquire_service): set the sender on the AcquireService reply * test/data/valid-config-files/debug-allow-all.conf.in: Make test server also listen on a UNIX socket so services can connect to it. 2003-04-06 Havoc Pennington * dbus/dbus-threads.c: Redo how the fake debug mutexes are done so it detects deadlocks and also we actually init threads when debugging. 2003-04-06 Havoc Pennington * dbus/dbus-server-unix.c (_dbus_server_new_for_domain_socket): save the domain socket name, and unlink it when we disconnect the server. Means that at least when we exit normally, we won't leave a bunch of junk in /tmp * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket): code cleanup (nicer memory management). (I was making a real change here but then didn't) 2003-04-06 Havoc Pennington * bus/bus.c (bus_context_new): fix wrong handling of server_data_slot_unref() in the error case. * dbus/dbus-internals.h (_dbus_assert): change so it passes "(condition) != 0" to _dbus_real_assert so that "_dbus_assert (pointer)" doesn't cause a warning * bus/main.c (main): accept --print-address option to print out the message bus address * dbus/dbus-sysdeps.c (_dbus_generate_random_ascii): export this * dbus/dbus-transport.c (_dbus_transport_open): special error for "tmpdir" option to unix: address on client side * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option to unix: address * configure.in (TEST_SOCKET_DIR): locate a temporary directory we can use to create sockets in the test suite. * bus/main.c (signal_handler): on SIGTERM, exit the daemon cleanly. To be used for testing. * dbus/dbus-spawn.c (babysit): use _dbus_set_signal_handler() * dbus/dbus-sysdeps.c (_dbus_set_signal_handler): new * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): handle trying to call this when there's no servers active 2003-04-05 Havoc Pennington * NEWS: update * configure.in: 0.8 2003-04-05 Havoc Pennington * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't crash on startup. Need to get "try starting the daemon" in the test suite I guess. ;-) * dbus/dbus-server.h, dbus/dbus-server.c: remove the stuff that tracked the number of open connections; it's better done in application-specific code as you want it to span all servers etc. 2003-04-05 Havoc Pennington * bus/Makefile.am (install-data-hook): add missing DESTDIR, patch from Colin Walters 2003-04-05 Havoc Pennington * doc/config-file.txt (Elements): fix docs of to reflect reality; in fact multiple mechanisms are allowed. * dbus/dbus-internals.c (_dbus_real_assert) (_dbus_real_assert_not_reached): move guts of _dbus_assert() and _dbus_assert_not_reached() into functions, so that they don't show up in basic block counts for test coverage, and don't use up as much disk space. Does mean slower execution speed though, so assumes --disable-asserts is the normal production case. 2003-04-05 Havoc Pennington * test/Makefile.am (dist-hook): also dist *.in files * NEWS: update * configure.in: 0.7 2003-04-05 Havoc Pennington * dbus/dbus-string.c: docs warning * dbus/dbus-spawn.c: missing docs * dbus/dbus-memory.c (struct ShutdownClosure): missing docs 2003-04-05 Havoc Pennington * bus/loop.c (bus_loop_iterate): fix the timeout code, using magic from GLib * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid to -1 once we've reaped the babysitter (_dbus_babysitter_handle_watch): do as much work as we can, not just one go of it * bus/activation.c: add code using DBusBabysitter so that we handle it when a service fails to start up properly. (bus_activation_service_created): don't remove the activation entries as we go, just let them get removed when we free the pending activation. Unref reply messages after sending them. 2003-04-05 Havoc Pennington * test/decode-gcov.c (main): print per-directory stats in the report * Makefile.am (coverage-report.txt): don't include test/* in gcov stats 2003-04-05 Havoc Pennington * Makefile.am (coverage-report.txt): add target "coverage-report.txt" * test/decode-gcov.c: hack up a little program to suck data out of gcov files. Yes this is sort of silly. * configure.in: define something in config.h and do an AM_CONDITIONAL when gcov is enabled 2003-04-04 Havoc Pennington * dbus/dbus-spawn.c, dbus/dbus-spawn.h: Change dbus_spawn to return a "babysitter" object that is used to monitor the status of the spawned process and reap it when required. * test/test-segfault.c, test/test-exit.c, test/test-sleep-forever.c: binaries that do various lame things, used in the test suite. * dbus/dbus-sysdeps.c: kill _dbus_errno_to_string() 2003-04-03 Havoc Pennington * dbus/dbus-spawn.c: Move dbus-spawn into a separate file in preparation for modifying it, dbus-sysdeps is getting a bit unmanageable. 2003-04-03 Havoc Pennington * bus/loop.h, bus/loop.c: make the mainloop an object so we can have multiple ones * bus/*.[hc]: adapt to mainloop change 2003-04-03 Havoc Pennington * bus/activation.c (load_directory): fix up memleaks (bus_activation_entry_free): free the entry * dbus/dbus-bus.c (dbus_bus_acquire_service): return an error if we get one from the message bus; fix memleaks. * dbus/dbus-message.c (dbus_set_error_from_message): new function 2003-04-03 Havoc Pennington * bus/config-parser.c (bus_config_parser_unref): free list of mechanisms, bug discovered by test suite enhancements (putting system.conf and session.conf into suite) * test/Makefile.am, test/test-service.c: add placeholder for a test service that we'll activate as part of test suite. Doesn't do anything yet. * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by setting NULL value, and use system malloc not dbus_malloc() when we have unavoidable memleakage. * dbus/dbus-bus.c (dbus_bus_get): fix bug where bus type of 0 didn't work, and support DBUS_BUS_ACTIVATION. * bus/activation.c (child_setup): pass our well-known bus type to the child * bus/config-parser.c: support to specify well-known type * doc/dbus-specification.sgml: document the env variables to locate well-known buses and find service activator 2003-04-02 Havoc Pennington * test/Makefile.am (all-local): add a rule to copy tests to builddir, so we can have generated tests. Use this to remove the silly hack for testing system.conf and session.conf. Will use this shortly to generate .service files pointing to test binaries. 2003-04-02 Havoc Pennington * dbus/dbus-string.c (set_length): fix a bug - we allocated max of current alloc and needed new length, not max of the doubled allocation and needed new length. Also, when building tests, don't do the double-allocation stuff, just realloc every time. 2003-04-02 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_file_get_contents): include filenames in error messages (_dbus_string_get_dirname): new (_dbus_sysdeps_test): new (_dbus_directory_open): include dirnames in error messages * bus/config-parser.c: interpret and and relative to config file location if the given filename is not absolute. * dbus/dbus-string.c (_dbus_string_find_byte_backward): new 2003-04-02 Havoc Pennington * bus/connection.c (bus_transaction_send_error_reply): set sender service for the error, and unref the reply on success * bus/activation.c: convert to use BusTransaction so OOM can be handled correctly (bus_activation_service_created): set sender of the message 2003-04-01 Havoc Pennington * bus/config-parser.c, bus/bus.c: implement and (at least mostly) * dbus/dbus-sysdeps.c (_dbus_change_identity): set the group ID first, then the user ID 2003-04-01 Havoc Pennington * dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new function * dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new * dbus/dbus-internals.c (_dbus_dup_string_array): new function * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the socket 0777, and unlink any existing socket. * bus/bus.c (bus_context_new): change our UID/GID and fork if the configuration file so specifies; set up auth mechanism restrictions * bus/config-parser.c (bus_config_parser_content): add support for option and fill in code for * bus/system.conf.in: add to default configuration, and limit auth mechanisms to EXTERNAL * doc/config-file.txt (Elements): add * dbus/dbus-sysdeps.c (_dbus_become_daemon): new function (_dbus_change_identity): new function 2003-03-31 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket) (_dbus_listen_unix_socket): fix off-by-one error in null termination spotted by Nalin 2003-03-31 Havoc Pennington * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): allow setting DBUS_TEST_HOMEDIR when tests are enabled, so we can test without having a real home directory available. 2003-03-31 Havoc Pennington * bus/Makefile.am (install-data-hook): create /var/run/dbus * bus/messagebus.in: add init script for Red Hat /etc/init.d * configure.in: add support for specifying a style of init script to install 2003-03-31 Havoc Pennington Fix some annoying DBusString API and fix all affected code. * dbus/dbus-string.c (_dbus_string_init): get rid of annoying max_length argument (_dbus_string_get_data): change to return string instead of using an out param (_dbus_string_get_const_data): ditto (_dbus_string_get_data_len): ditto (_dbus_string_get_const_data_len): ditto 2003-03-31 Havoc Pennington * bus/main.c (main): fix up the command line arguments to be nicer 2003-03-31 Havoc Pennington * dbus/Makefile.am (INCLUDES): use EXPANDED_LOCALSTATEDIR to define DBUS_SYSTEM_BUS_PATH as we want to compile in the same final location that lands in the config file * bus/config-loader-expat.c (bus_config_load): fix type of XML_Parser variable * doc/TODO: remove TODO item for dbus_bus_get() * dbus/dbus-bus.c (bus_data_free): add missing lock/unlock 2003-03-31 Havoc Pennington * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket) (_dbus_transport_new_for_tcp_socket): these didn't need the "server" argument since they are always client side * dbus/dbus-server.c (dbus_server_get_address): new function * bus/main.c (main): take the configuration file as an argument. * test/data/valid-config-files/debug-allow-all.conf: new file to use with dispatch.c tests for example * bus/test-main.c (main): require test data dir * bus/bus.c (bus_context_new): change this to take a configuration file name as argument * doc/config-file.txt (Elements): add * bus/system.conf, bus/session.conf: new files * dbus/dbus-bus.c (dbus_bus_get): look for system bus on well-known socket if none set * configure.in: create system.conf and session.conf 2003-03-30 Havoc Pennington * bus/config-parser.c: hacking * dbus/dbus-memory.c: don't use DBusList for the list of stuff to shut down, since it could cause weirdness with the DBusList lock * dbus/dbus-list.c (_dbus_list_test): add tests for the link-oriented stack routines (alloc_link): free the mempool if the first alloc from it fails * dbus/dbus-mempool.c (struct DBusMemBlock): fix alignment issue * dbus/dbus-string.c (UNICODE_VALID): sync new version of this from GLib (_dbus_string_skip_white): new * doc/config-file.txt (Elements): add 2003-03-28 Havoc Pennington * dbus/dbus-string.c (_dbus_string_copy_data_len) (_dbus_string_copy_data): new functions 2003-03-28 Anders Carlsson * dbus/dbus-bus.c: (bus_data_free), (dbus_bus_get): * dbus/dbus-bus.h: Add dbus_bus_get. * dbus/dbus-memory.c: Fix a doc comment. 2003-03-28 Havoc Pennington * bus/test.c (bus_test_flush_bus): remove the sleep from here, I think it may have just been superstition. Not sure. * dbus/dbus-string.c (_dbus_string_base64_decode): catch some OOM failures that were not being handled. * dbus/dbus-auth.c (process_auth): fix a memleak in OOM handling * dbus/dbus-memory.c: add ability to set number of mallocs in a row that will fail on out-of-memory. * dbus/dbus-internals.c (_dbus_test_oom_handling): convenience function for testing out-of-memory handling. * bus/config-loader-expat.c (memsuite): don't wrap the dbus allocation functions, they do map exactly to the expat ones. 2003-03-27 Havoc Pennington * bus/config-loader-libxml.c (bus_config_load): add another error check 2003-03-26 Anders Carlsson * doc/TODO: Add note about automatic service activation. * doc/dbus-specification.sgml: Rename the specification and clarify a few things. 2003-03-26 Anders Carlsson * Doxyfile.in: * dbus/dbus-address.c: * dbus/dbus-dict.c: * dbus/dbus-marshal.c: * dbus/dbus-server-debug-pipe.c: * dbus/dbus-transport-unix.c: Fix documentation warnings. 2003-03-26 Havoc Pennington * bus/test-main.c, dbus/dbus-test.c (main): check memleaks after every test so it's quick and easy to see which leaked, and so we test multiple dbus_shutdown() calls * configure.in: change configure.in XML stuff to also support expat * config-loader-libxml.c: some hacking * config-loader-expat.c: some hacking * config-parser.c: some hacking, plus tests 2003-03-25 Havoc Pennington * throughout - add more _DBUS_ASSERT_ERROR_IS_CLEAR * configure.in: add --with-xml option to specify XML library, right now only libxml is supported. * bus/config-loader-libxml.c, config-parser.c: sync some minor nonworking code between home and work, still just stubs 2003-03-24 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_set_fd_nonblocking): move to this file * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow NULL argument for "message" if the error is a well-known one, fill in a generic message in this case. * dbus/dbus-errors.h (DBusResultCode): Kill DBusResultCode in favor of DBusError * bus/test.c (bus_test_flush_bus): add * bus/policy.c (bus_policy_test): test code stub 2003-03-24 Havoc Pennington * bus/connection.c (bus_connections_setup_connection): set up the "can this user connect" function, but it always returns TRUE until we have a config file parser so we can have a config file that allows connections. 2003-03-23 Havoc Pennington * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with DBUS_BUILD_TESTS, actually alloc/free a block of memory for the mutex, so we can check for proper memory management and OOM handling. * dbus/dbus-dataslot.c: remove the mutex from DBusDataSlotAllocator and lock it manually when using it, to simplify fitting it into the global slots framework. * dbus/dbus-threads.c (init_static_locks): rework how we're handling global locks so they are easily shut down. * bus/policy.c (bus_policy_append_rule): fix * bus/test-main.c (main): check for memleaks * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make test suite check for memleaks * dbus/dbus-memory.c: add support in test mode for tracking number of outstanding blocks 2003-03-23 Havoc Pennington * bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny policies code * dbus/dbus-hash.h: add ULONG hash keys * dbus/dbus-sysdeps.c (_dbus_get_groups): new (_dbus_get_group_id): new function 2003-03-20 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_set_unix_user_function): new function (dbus_connection_get_unix_user): new function 2003-03-20 Havoc Pennington * bus/connection.c (bus_connection_send_oom_error): assert that message has a sender (connection_execute_transaction): ditto (bus_connection_preallocate_oom_error): fix to set the sender, and set recipient to the destination service, not the bus driver * bus/policy.c: hacking * dbus/dbus-message.c (dbus_message_service_is): new function (dbus_message_sender_is): new 2003-03-19 Havoc Pennington * bus/policy.c: start sketching code for policy restrictions on what connections can do. 2003-03-18 Havoc Pennington * doc/TODO: some notes on high-level todo items. Little nitpick stuff is all in @todo, so no need to add it here. * doc/config-file.txt: some notes on how config file might look 2003-03-18 Anders Carlsson * configure.in: 0.6 * NEWS: Update. 2003-03-17 Havoc Pennington * dbus/dbus-internals.h: add gcc attributes so that our printf-style functions warn on bad arguments to format * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf format bug * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix printf format bug 2003-03-17 Havoc Pennington * bus/test-main.c (main): make it print something as it runs so make check doesn't look stuck * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove from CVS, now obsolete 2003-03-17 Anders Carlsson * bus/dispatch.c: (bus_dispatch): Refetch the service name since it may have been reallocated when dbus_message_set_sender was called. * dbus/dbus-sysdeps.c: (_dbus_accept): Add address and address length variables and use them to stop valgrind from complaining. 2003-03-17 Havoc Pennington All tests pass, no memleaks, no valgrind complaints. * bus/test.c: refcount handler_slot * bus/connection.c (bus_connections_new): refcount connection_data_slot * dbus/dbus-auth-script.c (_dbus_auth_script_run): delete unused bytes so that auth scripts pass. * bus/dispatch.c: init message_handler_slot so it gets allocated properly * bus/dispatch.c (message_handler_slot_ref): fix memleak * dbus/dbus-server-debug-pipe.c (_dbus_server_debug_pipe_new): dealloc server_pipe_hash when no longer used for benefit of leak checking * dbus/dbus-auth.c (process_command): memleak fix * bus/dispatch.c (check_hello_message): memleak fix 2003-03-16 Havoc Pennington * dbus/dbus-bus.c (ensure_bus_data): fix double-unref of the data slot 2003-03-17 Anders Carlsson * bus/activation.c (bus_activation_activate_service): Append the pending activation entry to the list of pending activations. 2003-03-16 Havoc Pennington * bus/dispatch.c (bus_dispatch_test): remove double-unrefs of connections * dbus/dbus-address.c (create_entry): fix OOM handling when failing to alloc entry->method 2003-03-16 Havoc Pennington * dbus/dbus-watch.c (_dbus_watch_new): handle failure to malloc the watch * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): add some missing dbus_set_result * bus/dispatch.c (bus_dispatch_add_connection): handle failure to alloc the DBusMessageHandler * dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref the transport here, since we call this from the finalizer; it resulted in a double-finalize. * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug where we tried to use transport->connection that was NULL, happened when transport was disconnected early on due to OOM * bus/*.c: adapt to handle OOM for watches/timeouts * dbus/dbus-transport-unix.c: port to handle OOM during watch handling * dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a reference to unused bytes instead of a copy * dbus/dbus-server.c (dbus_server_handle_watch): return FALSE for out of memory * dbus/dbus-connection.c (dbus_connection_handle_watch): return FALSE on OOM * dbus/dbus-timeout.c (dbus_timeout_handle): return FALSE for out of memory 2003-03-16 Anders Carlsson * doc/dbus-specification.sgml: Document reply message for ActivateService. 2003-03-16 Anders Carlsson * bus/activation.c: (bus_pending_activation_entry_free), (bus_pending_activation_free), (bus_activation_new), (bus_activation_unref), (bus_activation_service_created), (bus_activation_activate_service): * bus/activation.h: * bus/bus.c: (bus_context_new): * bus/desktop-file.c: (new_section): * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_handle_activate_service): * bus/services.c: (bus_registry_new), (bus_registry_ensure): * bus/services.h: * dbus/dbus-connection.c: (dbus_connection_send_with_reply_and_block): * dbus/dbus-message.c: (dbus_message_append_args_valist): * dbus/dbus-protocol.h: Make activation work better. Now pending activations will be queued and the daemon won't try to activate services that are already registered. 2003-03-16 Havoc Pennington * dbus/dbus-bus.c (ensure_bus_data): handle failure to set connection data * dbus/dbus-memory.c (_dbus_initialize_malloc_debug): support DBUS_MALLOC_BACKTRACES to print trace when failing an alloc 2003-03-16 Havoc Pennington * dbus/dbus-string.c (_dbus_string_validate_utf8): oops, unbreak this. always run the test suite before commit... * bus/*: adapt to DBusConnection API changes * glib/dbus-gmain.c: adapt to DBusConnection API changes, requires renaming stuff to avoid dbus_connection_dispatch name conflict. * dbus/dbus-transport.c (_dbus_transport_queue_messages): new function * dbus/dbus-message.c (_dbus_message_loader_queue_messages): separate from _dbus_message_loader_return_buffer() * dbus/dbus-connection.c (dbus_connection_get_n_messages): remove this, because it's now always broken to use; the number of messages in queue vs. the number still buffered by the message loader is undefined/meaningless. Should use dbus_connection_get_dispatch_state(). (dbus_connection_dispatch): rename from dbus_connection_dispatch_message 2003-03-16 Havoc Pennington * dbus/dbus-string.c (_dbus_string_validate_utf8): copy in a real implementation 2003-03-16 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_with_reply_and_block): Decrease connection->n_incoming when removing an entry from the list. * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_set_boolean_array), (dbus_dict_set_int32_array), (dbus_dict_set_uint32_array), (dbus_dict_set_double_array), (dbus_dict_set_byte_array), (dbus_dict_set_string_array), (dbus_dict_get_boolean_array), (dbus_dict_get_double_array), (dbus_dict_get_byte_array): Handle NULL arrays and strings. Also add support for byte arrays. * dbus/dbus-marshal.c: (_dbus_marshal_byte_array), (_dbus_marshal_dict), (_dbus_demarshal_byte_array), (_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array), (_dbus_demarshal_double_array), (_dbus_demarshal_string_array), (_dbus_demarshal_dict), (demarshal_and_validate_len), (_dbus_marshal_validate_arg), (_dbus_marshal_test): * dbus/dbus-marshal.h: Add support for marshalling and demarshalling empty arrays and strings. * dbus/dbus-message.c: (dbus_message_append_args_valist), (dbus_message_append_string_array), (dbus_message_iter_get_boolean), (dbus_message_iter_get_boolean_array), (dbus_message_iter_get_int32_array), (dbus_message_iter_get_uint32_array), (dbus_message_iter_get_double_array), (dbus_message_iter_get_byte_array), (dbus_message_iter_get_string_array), (dbus_message_iter_get_dict), (check_message_handling): Add support for getting empty arrays and dicts. * dbus/dbus-string.c: (_dbus_string_validate_utf8): Don't do any validation at all for now, that's better than just checking for ASCII. * test/data/valid-messages/emptiness.message: New test message with lots of empty arrays. 2003-03-16 Havoc Pennington * dbus/dbus-connection.c (_dbus_connection_queue_received_message_link): new function that can't fail due to OOM * dbus/dbus-message.c (_dbus_message_loader_pop_message_link): new function pops a message together with a list link containing it. * dbus/dbus-transport-unix.c (queue_messages): use new link-based message queuing functions to avoid needing to alloc memory 2003-03-16 Havoc Pennington Oops - test code was only testing failure of around 30 of the mallocs in the test path, but it turns out there are 500+ mallocs. I believe this was due to misguided linking setup such that there was one copy of dbus_malloc etc. in the daemon and one in the shared lib, and only daemon mallocs were tested. In any case, the test case now tests all 500+ mallocs, and doesn't pass yet, though there are lots of fixes in this patch. * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix this so that it doesn't need to allocate memory, since it has no way of indicating failure due to OOM (and would be annoying if it did). * dbus/dbus-list.c (_dbus_list_pop_first_link): new function * bus/Makefile.am: rearrange to create two self-contained libraries, to avoid having libraries with overlapping symbols. that was resulting in weirdness, e.g. I'm pretty sure there were two copies of global static variables. * dbus/dbus-internals.c: move the malloc debug stuff to dbus-memory.c * dbus/dbus-list.c (free_link): free list mempool if it becomes empty. * dbus/dbus-memory.c (_dbus_disable_mem_pools): new function * dbus/dbus-address.c (dbus_parse_address): free list nodes on failure. * bus/dispatch.c (bus_dispatch_add_connection): free message_handler_slot when no longer using it, so memory leak checkers are happy for the test suite. * dbus/dbus-server-debug-pipe.c (debug_finalize): free server name * bus/bus.c (new_connection_callback): disconnect in here if bus_connections_setup_connection fails. * bus/connection.c (bus_connections_unref): fix to free the connections (bus_connections_setup_connection): if this fails, don't disconnect the connection, just be sure there are no side effects. * dbus/dbus-string.c (undo_alignment): unbreak this * dbus/dbus-auth.c (_dbus_auth_unref): free some stuff we were leaking (_dbus_auth_new): fix the order in which we free strings on OOM failure * bus/connection.c (bus_connection_disconnected): fix to not send ServiceDeleted multiple times in case of memory allocation failure * dbus/dbus-bus.c (dbus_bus_get_base_service): new function to get the base service name (dbus_bus_register_client): don't return base service name, instead store it on the DBusConnection and have an accessor function for it. (dbus_bus_register_client): rename dbus_bus_register() * bus/dispatch.c (check_hello_message): verify that other connections on the bus also got the correct results, not just the one sending hello 2003-03-15 Havoc Pennington Make it pass the Hello handling test including all OOM codepaths. Now to do other messages... * bus/services.c (bus_service_remove_owner): fix crash when removing owner from an empty list of owners (bus_registry_ensure): don't leave service in the list of a connection's owned services if we fail to put the service in the hash table. * bus/connection.c (bus_connection_preallocate_oom_error): set error flag on the OOM error. * dbus/dbus-connection.c (_dbus_connection_new_for_transport): handle _dbus_transport_set_connection failure * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): modify to create watches up front and simply enable/disable them as needed. (unix_connection_set): this can now fail on OOM * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept of enabling/disabling a watch or timeout. * bus/loop.c (bus_loop_iterate): don't touch disabled watches/timeouts * glib/dbus-gmain.c: adapt to enable/disable watches and timeouts 2003-03-15 Havoc Pennington * bus/dispatch.c (bus_dispatch_test): OK, now finally actually write useful test code, after all that futzing around ;-) Test does not yet pass because we can't handle OOM in _dbus_transport_messages_pending (basically, dbus_connection_preallocate_send() does not prealloc the write watch). To fix this, I think we need to add new stuff to set_watch_functions, namely a SetEnabled function so we can alloc the watch earlier, then enable it later. * dbus/Makefile.am (libdbus_convenience_la_SOURCES): move dbus-memory.c to the convenience lib * bus/test.c: rename some static functions to keep them clearly distinct from stuff in connection.c. Handle client disconnection. 2003-03-14 Havoc Pennington * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe transport, tests more of the real codepath. Set up clients with bus_setup_debug_client. * bus/test.c (bus_setup_debug_client): function to set up debug "clients" on the main loop * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe support * dbus/dbus-server.c (dbus_server_listen): add debug-pipe server type * dbus/dbus-server-debug.c: support a debug server based on pipes * dbus/dbus-sysdeps.c (_dbus_full_duplex_pipe): new function (_dbus_close): new function * configure.in: check for socketpair 2003-03-14 Havoc Pennington * dbus/dbus-memory.c: add a "detect buffer overwrites on free" cheesy hack * dbus/dbus-transport-debug.c: rework this a good bit to be less complicated. hopefully still works. * dbus/dbus-server-debug.c (handle_new_client): remove timeout manually * glib/dbus-gmain.c (timeout_handler): don't remove timeout after running it * dbus/dbus-message.c (dbus_message_copy): rename from dbus_message_new_from_message, fix it up to copy all the message fields, add test case * bus/dispatch.c (bus_dispatch_test): add some more test code, not quite passing yet 2003-03-14 Havoc Pennington * bus/loop.c (bus_loop_iterate): add this so we can "run loop until no work remains" in test code. (the large diff here is just code movement, no actual changes) * dbus/dbus-server-debug.c (DEFAULT_INTERVAL): change interval to 1, no point waiting around for test code. (_dbus_server_debug_accept_transport): unref the timeout after adding it (right?) * dbus/dbus-transport-debug.c (DEFAULT_INTERVAL): ditto 2003-03-13 Havoc Pennington * dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle out of memory * dbus/dbus-watch.c (_dbus_watch_list_set_functions): handle out of memory * dbus/dbus-connection.h: Make AddWatchFunction and AddTimeoutFunction return a bool so they can fail on out-of-memory * bus/bus.c (bus_context_new): set up timeout handlers * bus/connection.c (bus_connections_setup_connection): set up timeout handlers * glib/dbus-gmain.c: adapt to the fact that set_functions stuff can fail * bus/bus.c (bus_context_new): adapt to changes * bus/connection.c: adapt to changes * test/watch.c: adapt to DBusWatch changes * bus/dispatch.c (bus_dispatch_test): started adding this but didn't finish 2003-03-14 Anders Carlsson * bus/dispatch.c (send_service_nonexistent_error): Fix typo. 2003-03-13 Havoc Pennington * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c: set up a test framework as for the library 2003-03-12 Havoc Pennington Throughout: purge global variables, introduce BusActivation, BusConnections, BusRegistry, etc. objects instead. * bus/bus.h, bus/bus.c: introduce BusContext as a global message bus object * test/Makefile.am (TEST_BINARIES): disable bus-test for now, going to redo this a bit differently I think 2003-03-12 Havoc Pennington Mega-patch that gets the message bus daemon initially handling out-of-memory. Work still needed. Also lots of random moving stuff to DBusError instead of ResultCode. * dbus/dbus-list.c (_dbus_list_length_is_one): new function * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): use DBusError * dbus/dbus-bus.c: adapt to API changes, make it use DBusError not DBusResultCode * dbus/dbus-connection.c (dbus_connection_send): drop the result code here, as the only failure possible is OOM. * bus/connection.c (bus_connection_disconnect): rename bus_connection_disconnected as it's a notification only * bus/driver.c (bus_driver_handle_acquire_service): don't free "name" on get_args failure, should be done by get_args; don't disconnect client for bad args, just return an error. (bus_driver_handle_service_exists): ditto * bus/services.c (bus_services_list): NULL-terminate returned array * bus/driver.c (bus_driver_send_service_lost) (bus_driver_send_service_acquired): send messages from driver to a specific client to the client's unique name, not to the broadcast service. * dbus/dbus-message.c (decode_header_data): reject messages that contain no name field (_dbus_message_get_client_serial): rename to dbus_message_get_serial and make public (_dbus_message_set_serial): rename from set_client_serial (_dbus_message_set_reply_serial): make public (_dbus_message_get_reply_serial): make public * bus/connection.c (bus_connection_foreach): allow stopping iteration by returning FALSE from foreach function. * dbus/dbus-connection.c (dbus_connection_send_preallocated) (dbus_connection_free_preallocated_send) (dbus_connection_preallocate_send): new API for sending a message without possibility of malloc failure. (dbus_connection_send_message): rename to just dbus_connection_send (and same for whole function family) * dbus/dbus-errors.c (dbus_error_free): make this reinit the error * dbus/dbus-sysdeps.c (_dbus_exit): new function * bus/activation.c: handle/return errors * dbus/dbus-errors.h: add more DBUS_ERROR #define * dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents) (_dbus_directory_get_next_file): use DBusError instead of DBusResultCode (_dbus_result_from_errno): move to this file 2003-03-10 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_set_string): Take a length argument so we can marshal the correct string length. (_dbus_marshal_dict), (_dbus_demarshal_dict), (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg), (_dbus_marshal_test): * dbus/dbus-marshal.h: Add support for marshalling and demarshalling dicts. * dbus/dbus-message-builder.c: (_dbus_message_data_load): Add support for TYPE DICT. * dbus/dbus-message.c: (set_string_field): Adjust header padding. (dbus_message_append_args_valist), (dbus_message_append_dict), (dbus_message_get_args_valist), (dbus_message_iter_get_arg_type), (dbus_message_iter_get_dict), (_dbus_message_loader_return_buffer), (check_message_handling), (check_have_valid_message): * dbus/dbus-message.h: Add functions for setting and getting dicts. * dbus/dbus-protocol.h: Add DBUS_TYPE_DICT. * dbus/dbus.h: Add dbus-dict.h * doc/dbus-specification.sgml: Add information about how dicts are marshalled. * test/data/invalid-messages/dict-with-nil-value.message: * test/data/invalid-messages/too-short-dict.message: * test/data/valid-messages/dict-simple.message: * test/data/valid-messages/dict.message: Add sample messages containing dicts. 2003-03-08 Anders Carlsson * dbus/dbus-dict.h: Add DBUS_END_DECLS. 2003-03-07 Anders Carlsson * dbus/Makefile.am: * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new), (dbus_dict_get_keys), (insert_entry), (dbus_dict_set_boolean), (dbus_dict_set_int32), (dbus_dict_set_uint32), (dbus_dict_set_double), (dbus_dict_set_string), (dbus_dict_set_boolean_array), (dbus_dict_set_int32_array), (dbus_dict_set_uint32_array), (dbus_dict_set_double_array), (dbus_dict_set_string_array), (_dbus_dict_test): * dbus/dbus-dict.h: Fix according to comments from Havoc. 2003-03-06 Michael Meeks * configure.in: if we don't have kde-config, disable have_qt. 2003-03-07 Anders Carlsson * dbus/Makefile.am: Add dbus-dict.[ch] * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new), (dbus_dict_ref), (dbus_dict_unref), (dbus_dict_contains), (dbus_dict_remove), (dbus_dict_get_value_type), (dbus_dict_get_keys), (dbus_dict_put_boolean), (dbus_dict_put_int32), (dbus_dict_put_uint32), (dbus_dict_put_double), (dbus_dict_put_string), (dbus_dict_put_boolean_array), (dbus_dict_put_int32_array), (dbus_dict_put_uint32_array), (dbus_dict_put_double_array), (dbus_dict_put_string_array), (dbus_dict_get_boolean), (dbus_dict_get_int32), (dbus_dict_get_uint32), (dbus_dict_get_double), (dbus_dict_get_string), (dbus_dict_get_boolean_array), (dbus_dict_get_int32_array), (dbus_dict_get_uint32_array), (dbus_dict_get_double_array), (dbus_dict_get_string_array), (_dbus_dict_test): * dbus/dbus-dict.h: Add DBusDict implementation * dbus/dbus-test.c: (dbus_internal_do_not_use_run_tests): * dbus/dbus-test.h: Add _dbus_dict_test 2003-03-04 Havoc Pennington * test/data/auth/*: adapt to changes * dbus/dbus-auth-script.c (_dbus_auth_script_run): add USERID_BASE64 and change USERNAME_BASE64 to put in username not userid * dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent more stuff from being in a context name, to make the protocol simpler to deal with * dbus/dbus-errors.c (dbus_error_has_name): new function (dbus_error_is_set): new function * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1 * dbus/dbus-connection.c (dbus_connection_flush): also read messages during a flush operation * dbus/Makefile.am: remove dbus-md5 since it isn't currently used. 2003-03-05 Anders Carlsson * configure.in: Check for gethostbyname on Solaris. * dbus/dbus-transport.c: (_dbus_transport_open): Remove duplicate "tcp" entry. * doc/dbus-specification.sgml: Clarify some things. 2003-03-05 Anders Carlsson * dbus/dbus-auth.c: (send_rejected), (process_test_subdir): * dbus/dbus-keyring.c: (_dbus_keyring_new_homedir), (_dbus_keyring_test): * dbus/dbus-md5.c: (_dbus_md5_compute): * dbus/dbus-sha.c: (_dbus_sha_compute): Plug memory leaks. 2003-03-05 Anders Carlsson * README: Add some things. 2003-03-04 Anders Carlsson * dbus/dbus-message.c (dbus_message_append_args_valist): Add a break; after case DBUS_TYPE_BOOELAN. 2003-03-02 Havoc Pennington * test/break-loader.c (randomly_set_extreme_ints): add test that sets really huge and small integers * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add check that length of boolean array fits in the string, and that string has room for boolean value in single-bool case. * dbus/dbus-message-builder.c (_dbus_message_data_load): add optional value to "ALIGN" command which is what to fill the alignment with. * test/data/valid-messages/no-padding.message: add regression test for the message padding problem 2003-03-02 Havoc Pennington * dbus/dbus-message.c (decode_header_data): fix to always init message_padding, from Benjamin Dauvergne 2003-03-02 Havoc Pennington * configure.in: 0.5 * NEWS: Update. 2003-03-01 Joe Shaw * configure.in: Check for "struct cmsgcred" and try to access its members for BSD-like unices. * dbus/dbus-sysdeps.c (read_credentials_byte): Fold this back into _dbus_read_credentials_unix_socket(). (_dbus_read_credentials_unix_socket): Use recvmsg() instead of read() for reading the credential byte off the unix socket. Use struct cmsgcred on systems that support it. 2003-02-27 Alexander Larsson * glib/Makefile.am: * configure.in: Make gthreads-2.0 dependency optional. Don't build thread test if its not found. 2003-02-27 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_send_message_with_reply_and_block): fix doh! doh! doh! bug that resulted in never removing a reply from the queue, no wonder we called get_reply_serial so much ;-) * dbus/dbus-message.c (struct DBusMessage): cache reply serial and client serial instead of demarshaling them every time 2003-02-27 Havoc Pennington * dbus/dbus-marshal.c (_dbus_demarshal_int32): rewrite to be much more inlined, using dbus-string-private.h, speeds things up substantially * dbus/dbus-string.c (_dbus_string_free): apply align offset when freeing the string (_dbus_string_steal_data): fix for align offset (undo_alignment): new function 2003-02-26 Havoc Pennington All kinds of audit fixes from Owen, plus initial attempt to handle unaligned memory returned from malloc. * dbus/dbus-string.c (_dbus_string_init): clamp max length to leave room for align_offset and nul byte (fixup_alignment): function to track an align_offset and ensure real->str is aligned (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated, to allow a nul byte plus align offset (_dbus_string_lock): fix overflow issue (_dbus_string_init_const_len): add assertions on sanity of len, assign allocated to be ALLOCATION_PADDING larger than len (set_length): fixup the overflow handling (_dbus_string_get_data_len): fix overflow in assertion (open_gap): detect overflow in size of gap to be opened (_dbus_string_lengthen): add overflow check (_dbus_string_align_length): fix overflow with _DBUS_ALIGN_VALUE (_dbus_string_append): add overflow check (_dbus_string_append_unichar): overflow (_dbus_string_delete): fix overflow in assertion (_dbus_string_copy_len): overflow in assertion (_dbus_string_replace_len): overflows in assertions (_dbus_string_find): change to implement in terms of _dbus_string_find_to (_dbus_string_find_to): assorted fixage (_dbus_string_equal_c_str): assert c_str != NULL, fix logic so the function works (_dbus_string_ends_with_c_str): fix overflow thingy (_dbus_string_base64_encode): overflow fix (_dbus_string_validate_ascii): overflow (_dbus_string_validate_nul): overflow 2003-02-26 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_test): fix to work with DISABLE_ASSERTS 2003-02-26 Alexander Larsson * configure.in: Set DBUS_GLIB_THREADS_LIBS for apps using gthread-2.0 * dbus/dbus-connection.c: * dbus/dbus-connection.h: Fix _dbus_connection_acquire_io_path and _dbus_connection_acquire_dispatch. Add dbus_connection_set_wakeup_main_function and use it when queueing incoming and outgoing messages. * dbus/dbus-dataslot.c: Threadsafe usage of DBusDataSlotAllocator * dbus/dbus-message.c: (dbus_message_get_args_iter): dbus_new can fail. * dbus/dbus-server-unix.c: Add todo comment * glib/dbus-gmain.c: Implement the new wakeup functions for glib. * glib/Makefile.am: * glib/test-thread-client.c: * glib/test-thread-server.c: * glib/test-thread.h: Initial cut at some thread test code. Not really done yet. 2003-02-26 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_send_message_with_reply_and_block): fix crash where we ref'd the outgoing message instead of the returned reply * dbus/dbus-transport-unix.c (do_authentication): check read watch at the end of this function, so if we didn't need to read for authentication, we reinstall it for receiving messages * dbus/dbus-message.c (dbus_message_new_reply): allow replies to a NULL sender for peer-to-peer case * dbus/dbus-transport-unix.c (check_read_watch): handle !authenticated case correctly * glib/dbus-gmain.c: add support for DBusServer * dbus/dbus-server.c: add data slot support * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): check return values and handle errors * dbus/dbus-dataslot.c: factor out the data slot stuff from DBusConnection * Doxyfile.in (INPUT): add glib subdir * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename setup_with_g_main instead of hookup_with_g_main; write docs 2003-02-24 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_validate_arg): * dbus/dbus-message-builder.c: (_dbus_message_data_load): * dbus/dbus-message.c: (dbus_message_append_boolean), (dbus_message_append_boolean_array), (dbus_message_get_args_valist), (_dbus_message_test): * dbus/dbus-message.h: * doc/dbus-specification.sgml: Various fixes as pointed out by Havoc. * test/data/invalid-messages/bad-boolean-array.message: * test/data/invalid-messages/bad-boolean.message: Add invalid boolean value test cases. 2003-02-24 Anders Carlsson * dbus/dbus-internals.c: (_dbus_type_to_string): * dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg): * dbus/dbus-message-builder.c: (_dbus_message_data_load): * dbus/dbus-message.c: (dbus_message_append_args_valist), (dbus_message_append_boolean), (dbus_message_append_boolean_array), (dbus_message_get_args_valist), (dbus_message_iter_get_boolean), (dbus_message_iter_get_int32), (dbus_message_iter_get_uint32), (dbus_message_iter_get_double), (dbus_message_iter_get_boolean_array), (message_iter_test): * dbus/dbus-message.h: * dbus/dbus-protocol.h: * doc/dbus-specification.sgml: * test/data/valid-messages/lots-of-arguments.message: Add support for boolean and boolean array types. 2003-02-23 Havoc Pennington * dbus/dbus-keyring.c: finish most of this implementation and simple unit test * dbus/dbus-errors.c (dbus_set_error_const, dbus_set_error): make these barf if the error isn't cleared to NULL * dbus/dbus-sysdeps.c (_dbus_delete_file): set error on failure (_dbus_create_directory): new function * dbus/dbus-errors.c (dbus_set_error): fix warning * dbus/dbus-string.c (_dbus_string_hex_encode): new function (_dbus_string_hex_decode): new function (test_hex_roundtrip): test code * dbus/dbus-sha.c (_dbus_sha_compute): use dbus_string_hex_encode * dbus/dbus-md5.c (_dbus_md5_compute): use dbus_string_hex_encode * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use the save-to-temp/rename trick to atomically write the new file (_dbus_string_parse_uint): new function 2003-02-22 Havoc Pennington * test/Makefile.am (dist-hook): fix dist for test/data/sha-1 2003-02-22 Havoc Pennington * dbus/dbus-message.c (dbus_message_iter_get_string_array): (dbus_message_iter_get_byte_array): Fix up doxygen warnings * dbus/dbus-sha.c: add implementation of SHA-1 algorithm * dbus/test/data/sha-1: add US government test suite for SHA-1 2003-02-21 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): Make string arrays NULL-terminated. * dbus/dbus-memory.c: (dbus_free_string_array): * dbus/dbus-memory.h: New function for freeing NULL-terminated string arrays. * dbus/dbus-message-builder.c: (append_quoted_string), (_dbus_message_data_load): Add support for array types. * dbus/dbus-message.c: (check_message_handling): Add more types as test cases. * dbus/dbus-sysdeps.c: (_dbus_string_parse_int), (_dbus_string_parse_double): Add the start offset to the end offset. * test/data/valid-messages/lots-of-arguments.message: New test message with lots of arguments. 2003-02-21 Anders Carlsson * dbus/dbus-message.c: (dbus_message_append_nil), (dbus_message_append_int32), (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_int32_array), (dbus_message_append_uint32_array), (dbus_message_append_double_array), (dbus_message_append_byte_array), (dbus_message_append_string_array): Fix all out-of-memory handling in these functions. 2003-02-21 Anders Carlsson * dbus/dbus-message.c: (dbus_message_append_nil): Fix a silly. 2003-02-21 Anders Carlsson * dbus/dbus-message.c: (dbus_message_append_args_valist), (dbus_message_append_nil), (dbus_message_append_int32_array), (dbus_message_append_uint32_array), (dbus_message_append_double_array), (dbus_message_append_byte_array), (dbus_message_append_string_array), (dbus_message_get_args_valist), (dbus_message_iter_get_int32_array), (dbus_message_iter_get_uint32_array), (dbus_message_iter_get_double_array), (dbus_message_iter_get_byte_array), (dbus_message_iter_get_string_array): * dbus/dbus-message.h: Add functions for appending and getting arrays. 2003-02-21 Anders Carlsson * dbus/dbus-mempool.c (_dbus_mem_pool_new): Make the element size at least 8 bytes, fixes mempool tests on 64-bit machines. 2003-02-20 Alexander Larsson * dbus/dbus-transport-unix.c (unix_do_iteration): Unlock the connection mutex during a blocking select call. Add todo about how we need a way to wake up the select. * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: Add _dbus_connection_lock and _dbus_connection_unlock. 2003-02-19 Havoc Pennington * Doxyfile.in (PREDEFINED): put DOXYGEN_SHOULD_SKIP_THIS in Doxyfile.in, not Doxyfile * dbus/dbus-keyring.c: do some hacking on this * dbus/dbus-sysdeps.c (_dbus_delete_file): new * dbus/dbus-errors.c (dbus_set_error_const): do not call dbus_error_init (dbus_set_error): remove dbus_error_init, check for message == NULL *before* we sprintf into it, and add @todo about including system headers in this file * dbus/dbus-sysdeps.c (_dbus_create_file_exclusively): new * dbus/dbus-errors.h (DBUS_ERROR_FAILED): add * dbus/dbus-sysdeps.c (get_user_info): break this function out to get various bits of user information based on either username or user ID (_dbus_homedir_from_username): new function 2003-02-19 Anders Carlsson * configure.in: Add check for nonposix getpwnam_r * dbus/dbus-mempool.c: (_dbus_mem_pool_new): Align the pool element size to a sizeof (void *) boundary. * dbus/dbus-sysdeps.c: (_dbus_setenv), (_dbus_connect_unix_socket), (_dbus_listen_unix_socket), (_dbus_credentials_from_username): General Solaris fixes. * test/data/valid-messages/simplest-manual.message: Explicitly state that we want little-endian packing. 2003-02-19 Mikael Hallendal * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket): Added to create a transport connecting using a tcp/ip socket. * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): Added to connect to a tcp socket at given host and port. (_dbus_listen_tcp_socket): added to listen on tcp socket for given hostname and port. * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): Added to create a server listening on a TCP/IP socket. 2003-02-19 Havoc Pennington Throughout: mop up all the Doxygen warnings and undocumented stuff. * dbus/dbus-sysdeps.c (do_exec): do not use execvp, we don't want to search any paths. * dbus/dbus-threads.c: move global mutex initializers to dbus-internals.h, multiple prototypes was confusing doxygen besides being kind of ugly * Doxyfile (PREDEFINED): have Doxygen define DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from docs with #ifndef DOXYGEN_SHOULD_SKIP_THIS (do not abuse the feature! it's for stuff like the autogenerated macros in dbus-md5.c, not just for things you don't feel like documenting...) 2003-02-18 Havoc Pennington * dbus/dbus-string.c (_dbus_string_zero): new function * dbus/dbus-md5.c: include MD5 implementation by L. Peter Deutsch, wrap it in some dbus-friendly API * dbus/dbus-types.h: add 16-bit types 2003-02-18 Joe Shaw * dbus/dbus-auth.c (handle_server_data_stupid_test_mech): Just get credentials from our currently running process. (get_word): Fix a buglet where we were copying the entire length instead of relative to our position. * dbus/dbus-hash.c (_dbus_hash_test): Don't try to allocate the keys on the stack... it's 640k of data. * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): Always read the credentials byte off the socket, even if we don't have SO_PEERCRED. (_dbus_poll): Implement poll() using select() for systems which don't have it. * glib/test-dbus-glib.c (main): Print out an error if no parameters are given. * test/data/auth/fallback.auth-script: Added. Tests that a client can fallback to a secondary auth mechanism if the first fails. 2003-02-18 Havoc Pennington * AUTHORS: add Alex 2003-02-17 Havoc Pennington * doc/dbus-specification.sgml: lots of cosmetic cleanups/rearrangement, add assorted FIXME, change DBUS_ADDRESS env variable to DBUS_BUS_ADDRESS, s/client/application/, s/server/bus/ (except in authentication section). Add a section "Message Bus Message Routing" 2003-02-17 Anders Carlsson Release 0.4 * NEWS: Update 2003-02-17 Anders Carlsson * doc/dbus-specification.sgml: Specification updates. 2003-02-17 Anders Carlsson * bus/activation.c: (bus_activation_init), (child_setup), (bus_activation_activate_service): * bus/activation.h: * bus/main.c: (main): Set DBUS_ADDRESS environment variable. * dbus/dbus-errors.c: (dbus_set_error): Don't use va_copy since that's a C99 feature. * dbus/dbus-sysdeps.c: (_dbus_setenv), (do_exec), (_dbus_spawn_async): * dbus/dbus-sysdeps.h: Add child_setup_func to _dbus_spawn_async. * doc/dbus-specification.sgml: Update specification. * test/spawn-test.c: (setup_func), (main): Fix test. 2003-02-17 Alexander Larsson * dbus/dbus-connection.c (_dbus_connection_handler_destroyed_locked): Added todo. 2003-02-17 Anders Carlsson * doc/.cvsignore: * doc/Makefile.am: * doc/dbus-test-plan.sgml: Add test plan document. * test/Makefile.am: Fix distcheck. 2003-02-17 Anders Carlsson * dbus/dbus-message.c: (decode_header_data), (_dbus_message_loader_return_buffer): Set the header padding amount when loading a message. 2003-02-16 Anders Carlsson * bus/dispatch.c: (send_one_message): Only send broadcast messages to registered connections. * dbus/dbus-message.c: (dbus_message_name_is): * dbus/dbus-message.h: New convenience function. * dbus/dbus-transport-debug.c: (do_reading): Only dispatch one message per run. * test/Makefile.am: * test/bus-test.c: (new_connection_callback), (die), (test_hello_client1_handler), (test_hello_client2_handler), (test_hello_replies), (main): * test/bus-test-loop.[ch]: Add these. 2003-02-16 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix backward conditional 2003-02-16 Alexander Larsson * dbus/dbus-connection.c: Implement sent_message_with_reply. (with_reply_and block is still busted). Made dispatch_message not lose message if OOM. * dbus/dbus-errors.h: Add NoReply error (for reply timeouts). 2003-02-16 Alexander Larsson * dbus/dbus-hash.c (_dbus_hash_table_unref): Actually free keys and values when destroying hashtable. 2003-02-16 Anders Carlsson * dbus/dbus-auth.c: (client_try_next_mechanism): Plug a leak. * dbus/dbus-threads.c: (dbus_condvar_wait_timeout): Return TRUE if there's no thread implementation around. * glib/dbus-gmain.c: (free_source), (dbus_connection_hookup_with_g_main): Make sure to remove the GSource when the connection is finalized. 2003-02-16 Anders Carlsson * bus/dispatch.c: (bus_dispatch_message_handler): * dbus/dbus-errors.h: Return an error if someone tries to send a message to a service that doesn't exist. 2003-02-16 Anders Carlsson * bus/activation.c: (load_directory), (bus_activation_init), (bus_activation_activate_service): * bus/activation.h: * bus/driver.c: (bus_driver_handle_activate_service), (bus_driver_handle_message): More work on the activation handling. * dbus/dbus-errors.h: Add some error messages * dbus/dbus-message.c: (dbus_message_new_error_reply): * dbus/dbus-message.h: New function that creates an error message. * dbus/dbus-protocol.h: Add ACTIVATE_SERVER message. * dbus/dbus-server-unix.c: (unix_handle_watch), (_dbus_server_new_for_domain_socket): Call _dbus_fd_set_close_on_exec. * dbus/dbus-sysdeps.c: (make_pipe), (do_exec), (_dbus_spawn_async), (_dbus_disable_sigpipe), (_dbus_fd_set_close_on_exec): * dbus/dbus-sysdeps.h: Add _dbus_fd_set_close_on exec function. Also add function that checks that all open fds are set to close-on-exec and warns otherwise. * dbus/dbus-transport-unix.c: (_dbus_transport_new_for_domain_socket): Call _dbus_fd_set_close_on_exec. 2003-02-16 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_set_change_sigpipe): allow people to avoid setting SIGPIPE to SIG_IGN (_dbus_connection_new_for_transport): disable SIGPIPE unless we've been asked not to 2003-02-15 Anders Carlsson * dbus/dbus-list.c: (_dbus_list_append_link), (_dbus_list_prepend_link): * dbus/dbus-memory.c: (dbus_malloc), (dbus_malloc0), (dbus_realloc): Warning fixes. 2003-02-15 Anders Carlsson * bus/Makefile.am: * bus/activation.c: (bus_activation_entry_free), (add_desktop_file_entry), (load_directory), (bus_activation_init): * bus/activation.h: * bus/main.c: (main): Add simple activation support, doesn't work yet though. 2003-02-15 Zack Rusin * qt/dbus-qthread.cpp: small casting fix 2003-02-15 Anders Carlsson * dbus/dbus-errors.c: (dbus_set_error): * dbus/dbus-errors.h: Add a few errors and make dbus_set_error void. * dbus/dbus-sysdeps.c: (_dbus_errno_to_string), (close_and_invalidate), (make_pipe), (write_err_and_exit), (read_ints), (do_exec), (_dbus_spawn_async): * dbus/dbus-sysdeps.h: Add _dbus_spawn_async. * test/spawn-test.c: (main): Test for _dbus_spawn_async. 2003-02-15 Anders Carlsson * dbus/dbus-internals.h: Fix build without tests. * dbus/dbus-list.c: (alloc_link): Fix a segfault when a malloc fails. * dbus/dbus-memory.c: (initialize_malloc_debug), (dbus_malloc), (dbus_malloc0), (dbus_realloc): Add support for malloc debugging. 2003-02-15 Alexander Larsson * dbus/dbus-threads.c: * dbus/dbus-threads.h: Add condvars. Remove static mutext from API. Implement static mutexes by initializing them from threads_init. * glib/dbus-gthread.c: * qt/dbus-qthread.cpp: Update with the thread api changes. * dbus/dbus-list.c: * dbus/dbus-list.h: Turn StaticMutex into normal mutex + init function. Export new functions _dbus_list_alloc_link, _dbus_list_free_link, _dbus_list_append_link, _dbus_list_prepend_link * dbus/dbus-sysdeps.c: * dbus/dbus-sysdeps.h: New type dbus_atomic_t, and new functions _dbus_atomic_inc, _dbus_atomic_dec. Only slow fallback implementation at the moment. * dbus/dbus-protocol.h: Add DBUS_MESSAGE_LOCAL_DISCONNECT define * dbus/dbus-message.c: Make ref/unref atomic. Fix some docs. * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: * dbus/dbus-connection.h: Make threadsafe. Change _peek to _borrow,_return & _steal_borrowed. Change disconnect callback to event. Make dbus_connection_dispatch_messages reentrant. * dbus/dbus-transport.c: Don't ref the connection on calls to the transport implementation. * dbus/dbus-message-handler.c: Make threadsafe. * glib/dbus-gmain.c: Don't use peek_message anymore * test/Makefile.am: * test/debug-thread.c: * test/debug-thread.h: Simple thread implementation that asserts() on deadlocks in single-threaded code. * test/bus-test.c: (main) Call debug_threads_init. * test/watch.c: Use disconnect message instead of disconnect callback. * bus/connection.c: * bus/connection.h: Don't call dbus_connection_set_disconnect_function. Instead export bus_connection_disconnect. * bus/dispatch.c: Call bus_connection_disconnect when we get a disconnected message. 2003-02-15 Havoc Pennington * dbus/dbus-message.c (dbus_message_new): fool around with the docs 2003-02-14 Havoc Pennington * dbus/dbus-mempool.c: fail if the debug functions so indicate * dbus/dbus-memory.c: fail if the debug functions indicate we should * dbus/dbus-internals.c (_dbus_set_fail_alloc_counter) (_dbus_decrement_fail_alloc_counter): debug functions to simulate memory allocation failures 2003-02-14 Havoc Pennington * dbus/dbus-errors.h (struct DBusError): add a word of padding to DBusError 2003-02-13 Anders Carlsson * bus/driver.c: (bus_driver_handle_hello): * bus/driver.h: * bus/services.c: (bus_service_lookup): Reorder message sending so we get a more sane order. * test/bus-test.c: (message_handler): Fix tyop. 2003-02-13 Anders Carlsson * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_send_service_lost), (bus_driver_send_service_acquired), (bus_driver_handle_hello), (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_handle_acquire_service), (bus_driver_handle_service_exists): * dbus/dbus-bus.c: (dbus_bus_register_client), (dbus_bus_acquire_service), (dbus_bus_service_exists): * dbus/dbus-errors.c: (dbus_result_to_string): * dbus/dbus-errors.h: * dbus/dbus-message.c: (dbus_message_append_args), (dbus_message_append_args_valist), (dbus_message_get_args), (dbus_message_get_args_valist), (dbus_message_get_args_iter), (dbus_message_iter_get_arg_type), (dbus_message_iter_get_string), (dbus_message_iter_get_byte_array), (dbus_message_iter_get_string_array), (message_iter_test), (check_message_handling), (_dbus_message_test): * dbus/dbus-message.h: * test/bus-test.c: (main): Change fields to arguments in messages, so that they won't be confused with header fields. * glib/test-dbus-glib.c: (main): Remove append_fields from hello message. 2003-02-13 Anders Carlsson * dbus/dbus-errors.c: * dbus/dbus-message.c: * dbus/dbus-string.c: Documentation fixes. 2003-02-13 Anders Carlsson * glib/dbus-gmain.c: (timeout_handler), (add_timeout), (remove_timeout): Implement support for timeouts in dbus-glib. 2003-02-13 Anders Carlsson * dbus/dbus-message-builder.c: (_dbus_message_data_load): * dbus/dbus-message.c: (process_test_subdir): * test/break-loader.c: (find_breaks_based_on): Plug some memory leaks. 2003-02-13 Richard Hult * bus/main.c: Fix build. * dbus/dbus-errors.h: * dbus/dbus-errors.c: Fix copyright for Anders. 2003-02-13 Anders Carlsson * bus/Makefile.am: Add utils.[ch] * bus/connection.c: (bus_connection_foreach): Fix a warning. * bus/desktop-file.c: (grow_lines_in_section), (grow_sections), (unescape_string), (new_section), (parse_section_start), (parse_key_value), (report_error), (bus_desktop_file_load), (bus_desktop_file_get_string): * bus/desktop-file.h: Use DBusError for error reporting. * bus/dispatch.c: (send_one_message), (bus_dispatch_message_handler): * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_send_service_lost), (bus_driver_send_service_acquired), (bus_driver_handle_hello), (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_handle_acquire_service), (bus_driver_handle_service_exists): * bus/loop.c: (bus_loop_run): * bus/main.c: Use BUS_HANDLE_OOM instead of _DBUS_HANDLE_OOM. * bus/utils.c: (bus_wait_for_memory): * bus/utils.h: New files with general utility functions. * dbus/dbus-internals.h: Remove _DBUS_HANDLE_OOM. 2003-02-13 Anders Carlsson * dbus/dbus-errors.c: (dbus_result_to_string), (dbus_error_init), (dbus_error_free), (dbus_set_error_const), (dbus_set_error): * dbus/dbus-errors.h: Add DBusError structure. 2003-02-13 Anders Carlsson * test/data/valid-messages/standard-acquire-service.message: * test/data/valid-messages/standard-hello.message: * test/data/valid-messages/standard-list-services.message: * test/data/valid-messages/standard-service-exists.message: Add some standard messages. 2003-02-13 Anders Carlsson * bus/driver.c: (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_handle_acquire_service), (bus_driver_handle_service_exists), (bus_driver_handle_message): Update for API changes in libdbus. * dbus/dbus-message.c: (dbus_message_new_reply): * dbus/dbus-message.h: Remove the name argument. The spec states that replies shouldn't have a name. 2003-02-13 Anders Carlsson * bus/desktop-file.c: (parse_section_start), (parse_key_value), (report_error), (bus_desktop_file_load), (lookup_section), (lookup_line), (bus_desktop_file_get_raw), (bus_desktop_file_get_string): * bus/desktop-file.h: Some fixes, and new functions for getting a key value from a section. 2003-02-13 Havoc Pennington * test/data/auth/fail-after-n-attempts.auth-script: new test * dbus/dbus-auth.c (send_rejected): shutdown_mech() when we reject the client. 2003-02-13 Havoc Pennington * dbus/dbus-auth.c (handle_server_data_external_mech): args to dbus_credentials_match were backward * dbus/dbus-auth-script.c (_dbus_auth_script_run): support NO_CREDENTIALS and ROOT_CREDENTIALS * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine into here. Never process more commands after we've reached an end state; store further data as unused bytes. * test/data/auth/*: add more auth tests * dbus/dbus-auth-script.c (_dbus_auth_script_run): support EXPECT command to match exact string and EXPECT_UNUSED to match unused bytes * test/Makefile.am (dist-hook): fix to dist all the test stuff 2003-02-12 Havoc Pennington * dbus/dbus-string.c (_dbus_string_pop_line): fix to also strip \r off of popped lines * dbus/dbus-auth.c (_dbus_auth_test): write code to run auth scripts * dbus/dbus-auth-script.c (_dbus_auth_script_run): when doing a SEND, append \r\n 2003-02-12 Havoc Pennington * dbus/Makefile.am: remove break-loader from the build, since it moved. * configure.in: add --enable-gcov to turn on coverage profiling flags and disable optimization 2003-02-10 Havoc Pennington * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync initial cut at test framework for DBusAuth from laptop. Doesn't quite work yet but it compiles and I need to get it off the 266mhz laptop. ;-) * dbus/dbus-server-debug.c (_dbus_server_debug_accept_transport): fix a memleak in error case 2003-02-12 Anders Carlsson * bus/Makefile.am: * bus/desktop-file.c: * bus/desktop-file.h: Add a desktop file parser. 2003-02-11 Zack Rusin * qt/message.[h|cpp]: sample implementation of the KDE wrapper for DBusMessage 2003-02-09 Zack Rusin * test/bus-test.c: make_it_compile * doc/dbus-specification.sgml: minimal semantic fix 2003-02-06 Anders Carlsson Release 0.3 * NEWS: Update 2003-02-06 Anders Carlsson * dbus/Makefile.am: * dbus/dbus-break-loader.c: * test/Makefile.am: * test/break-loader.c: Move dbus-break-loader to test/ and rename it to break-loader. 2003-02-02 Havoc Pennington * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files for code to manage cookies in your home directory * dbus/dbus-sysdeps.c (_dbus_generate_random_bytes): new function * dbus/dbus-auth.c (get_state): impose a maximum number of tries to authenticate, then disconnect the client. 2003-02-03 Alexander Larsson * dbus/dbus-message.c (dbus_message_append_fields): Correct docs. 2003-02-02 Anders Carlsson * doc/dbus-specification.sgml: Update address format section. 2003-02-02 Anders Carlsson * test/Makefile.am: * test/bus-test.c: (get_time), (add_timeout), (remove_timeout), (message_handler), (new_connection_callback), (loop_quit), (loop_run), (main): Add bus test. 2003-02-02 Anders Carlsson * bus/driver.c: (bus_driver_handle_service_exists): Simplify the code a bit. * dbus/dbus-bus.c: (dbus_bus_service_exists): Fix a silly. 2003-02-02 Anders Carlsson * bus/Makefile.am: Add libdbus-daemon.la and link to it. 2003-02-01 James Willcox * bus/driver.c: (bus_driver_handle_own_service): Actually include the service reply code in the message. 2003-02-02 Anders Carlsson * bus/driver.c: (bus_driver_handle_service_exists): Don't unref the incoming message. 2003-02-02 Anders Carlsson * dbus/dbus.h: Add dbus-address.h and dbus-bus.h 2003-02-02 Anders Carlsson * dbus/dbus-server.c: (dbus_server_listen): * dbus/dbus-transport.c: (_dbus_transport_open): ifdef out the calls to the debug transport and server. 2003-02-02 Alexander Larsson * dbus/dbus-watch.c (dbus_watch_get_flags): Add note in the docs that ERROR or HANGUP won't be returned and are assumed always on. * glib/dbus-gmain.c (add_watch): Always add IO_ERR | IO_HUP * dbus/dbus-message.h: Add semicolon after dbus_message_iter_get_string_array(). Makes qt code build again 2003-02-01 Anders Carlsson * bus/driver.c: (create_unique_client_name), (bus_driver_handle_hello): Don't take a name, just use a numeric id to identify each client. * dbus/Makefile.am: * dbus/dbus-bus.c: (dbus_bus_register_client), (dbus_bus_acquire_service), (dbus_bus_service_exists): * dbus/dbus-bus.h: Add new convenience functions for communicating with the bus. * dbus/dbus-message.h: * dbus/dbus-protocol.h: Fix a typo. 2003-02-01 Alexander Larsson * dbus/dbus-message.c (dbus_message_append_fields): Add some more doc comments. 2003-02-01 Havoc Pennington * dbus/dbus-break-loader.c (randomly_modify_length): change a 4-byte value in the message as if it were a length * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): don't set execute bit on saved files 2003-02-01 Havoc Pennington * dbus/dbus-break-loader.c (main): new program to find messages that break the loader. * dbus/dbus-sysdeps.c (_dbus_string_append_uint): new function * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): new function * dbus/dbus-string.c (_dbus_string_set_byte): new 2003-01-31 Havoc Pennington * dbus/dbus-message.c: refactor the test code to be more general, in preparation for writing a "randomly permute test cases to try to break the loader" program. 2003-01-31 Havoc Pennington * doc/dbus-specification.sgml: work on the specification * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check the protocol version of the message. * dbus/dbus-protocol.h: drop special _REPLY names, the spec no longer specifies that. (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not 1/2/3/4) * dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): add missing "break" for DBUS_TYPE_NIL, remove @todo 2003-01-31 Havoc Pennington * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename just set_is_error/get_is_error as this is a commonly-used function, and write docs. 2003-01-31 Anders Carlsson * dbus/dbus-address.c: (dbus_address_entry_free): Free key and value lists. * dbus/dbus-internals.c: (_dbus_type_to_string): Add the types we didn't have. * dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg): Add NIL types. * dbus/dbus-message.c: (dbus_message_set_sender): Remove todo about being able to set sender to NULL. (dbus_message_set_is_error_reply), (dbus_message_get_is_error_reply): * dbus/dbus-message.h: New functions. * dbus/dbus-protocol.h: Add error reply flag. * test/data/valid-messages/opposite-endian.message: Add NIL type to test. 2003-01-31 Havoc Pennington * doc/dbus-specification.sgml: fully specify the header. Add flags and major protocol version, and change header/body len to unsigned. * dbus/dbus-message-builder.c (append_saved_length): append length as uint32 * dbus/dbus-message.c (dbus_message_create_header): change header length and body length to unsigned. Add the new fields from the spec (_dbus_message_loader_return_buffer): unsigned header/body len 2003-01-30 Havoc Pennington * dbus/dbus-auth.c: rework to use only REJECTED, no MECHANISMS * doc/dbus-sasl-profile.txt: drop MECHANISMS and just use REJECTED, suggested by Mark McLoughlin 2003-01-30 Havoc Pennington * dbus/dbus-server.c (dbus_server_listen): @todo about how we need a better way to report errors here. e.g. "unix address lacks path" or something. also "no such file" when the path doesn't exist, etc. * dbus/dbus-address.c (dbus_address_entries_free): add @todo about leaking list nodes (dbus_parse_address): add @todo about documenting address format, and allowing , and ; to be escaped 2003-01-30 Anders Carlsson * dbus/Makefile.am: Add dbus-address.[ch] * dbus/dbus-address.c: (dbus_address_entry_free), (dbus_address_entries_free), (create_entry), (dbus_address_entry_get_method), (dbus_address_entry_get_value), (dbus_parse_address), (_dbus_address_test): * dbus/dbus-address.h: New files for dealing with address parsing. * dbus/dbus-connection.c: Document timeout functions. * dbus/dbus-message.c: Document dbus_message_new_from_message. * dbus/dbus-server-debug.c: Document. * dbus/dbus-server.c: (dbus_server_listen): Parse address and use correct server implementation. * dbus/dbus-string.c: (_dbus_string_find_to), (_dbus_string_test): * dbus/dbus-string.h: New function with test. * dbus/dbus-test.c: (dbus_internal_symbol_do_not_use_run_tests): * dbus/dbus-test.h: Add address tests. * dbus/dbus-transport-debug.c: Document. * dbus/dbus-transport.c: (_dbus_transport_open): Parse address and use correct transport implementation. 2003-01-30 Havoc Pennington * dbus/dbus-message.c: use message->byte_order instead of DBUS_COMPILER_BYTE_ORDER throughout. (dbus_message_create_header): pad header to align the start of the body of the message to 8-byte boundary * dbus/dbus-marshal.h: make all the demarshalers take const DBusString arguments. * dbus/dbus-message.c (_dbus_message_loader_return_buffer): validate message args here, so we don't have to do slow validation later, and so we catch bad messages as they are incoming. Also add better checks on header_len and body_len. Also fill in message->byte_order * dbus/dbus-string.c (_dbus_string_validate_utf8): new (not implemented properly) (_dbus_string_validate_nul): new function to check all-nul * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename get_arg_end_pos and remove all validation (_dbus_marshal_validate_arg): actually do validation here. 2003-01-29 Havoc Pennington * dbus/dbus-message.c (check_message_handling): fix assertion failure on set_client_serial 2003-01-28 Havoc Pennington * dbus/dbus-server-debug.c: Add doc section comments * dbus/dbus-transport-debug.c: add doc section comments 2003-01-28 Havoc Pennington * dbus/dbus-string.c (_dbus_string_base64_decode): append bytes in the reverse order from how I had it (_dbus_string_base64_encode): reverse encoding order. I was basically byteswapping everything during encoding. 2003-01-28 Anders Carlsson * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: (_dbus_connection_add_timeout), (_dbus_connection_remove_timeout): Add functions for adding and removing timeouts. * dbus/dbus-message.c: (dbus_message_new_from_message): Add new function that takes a message and creates an exact copy of it, but with the refcount set to 1. (check_message_handling): Fix build error. * dbus/dbus-server-protected.h: * dbus/dbus-server.c: (_dbus_server_init_base), (_dbus_server_finalize_base), (_dbus_server_add_timeout), (dbus_server_set_timeout_functions): (_dbus_server_remove_timeout): New functions so that a server can add and remove timeouts. (dbus_server_listen): Add commented out call to dbus_server_debug_new. * dbus/dbus-timeout.c: (_dbus_timeout_new): Actually set the handler, doh. * dbus/dbus-transport.c: (_dbus_transport_open): Add commented out call to dbus_transport_debug_client_new. * dbus/Makefile.am: Add dbus-transport-debug.[ch] and dbus-server-debug.[ch] 2003-01-28 Havoc Pennington * dbus/dbus-message.c (check_message_handling): function to check on the loaded message, iterates over it etc. 2003-01-28 Havoc Pennington * test/Makefile.am (dist-hook): fix make distdir * dbus/Makefile.am (TESTS_ENVIRONMENT): fix make check 2003-01-27 Havoc Pennington * dbus/dbus-mempool.c (time_for_size): replace printf with _dbus_verbose * dbus/dbus-message-builder.c (_dbus_message_data_load): allow empty lines; fix the SAVE_LENGTH stuff to be START_LENGTH/END_LENGTH so it actually works; couple other bugfixes * test/Makefile.am (dist-hook): add dist-hook for .message files * dbus/dbus-string.c (DBUS_STRING_COPY_PREAMBLE): source of a copy can be constant or locked. (_dbus_string_free): allow freeing a const string as documented/intended * dbus/dbus-sysdeps.c (_dbus_concat_dir_and_file): utility * dbus/dbus-test-main.c (main): take an argument which is the directory containing test data * dbus/dbus-message.c (_dbus_message_test): pass a test_data_dir argument to this and load all the messages in test/data/ checking that they can be loaded or not loaded as appropriate. 2003-01-27 Anders Carlsson * bus/dispatch.c: (bus_dispatch_message_handler): Dispatch messages sent to services. * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_send_service_lost), (bus_driver_send_service_acquired): Add helper functions for sending service related messages. (bus_driver_send_welcome_message): Send HELLO_REPLY instead of WELCOME. (bus_driver_handle_list_services): Send LIST_SERVICES_REPLY instead of SERVICES. (bus_driver_handle_own_service), (bus_driver_handle_service_exists): New message handlers. (bus_driver_handle_message): Invoke new message handlers. (bus_driver_remove_connection): Don't remove any services here since that's done automatically by bus_service_remove_owner now. * bus/driver.h: New function signatures. * bus/services.c: (bus_service_add_owner): Send ServiceAcquired message if we're the only primary owner. (bus_service_remove_owner): Send ServiceAcquired/ServiceLost messages. (bus_service_set_prohibit_replacement), (bus_service_get_prohibit_replacement): Functions for setting prohibit replacement. (bus_service_has_owner): New function that checks if a connection is in the owner queue of a certain service. * bus/services.h: Add new function signatures. * dbus/dbus-list.c: (_dbus_list_test): Add tests for _dbus_list_remove_last and traversing the list backwards. * dbus/dbus-list.h: Fix a typo in _dbus_list_get_prev_link, if we're at the first element we can't go any further, so return NULL then. * dbus/dbus-protocol.h: Add new messages, service flags and service replies. 2003-01-26 Havoc Pennington * dbus/dbus-message-builder.c: implement, completely untested. * test/data/*: add data to be used in testing. ".message" files are our simple loadable text format. ".message-raw" will be binary dumps of messages. * dbus/dbus-string.c (_dbus_string_starts_with_c_str): new 2003-01-26 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_file_get_contents): new function * dbus/dbus-errors.c (dbus_result_to_string): add file errors * dbus/dbus-message-builder.c: new file, will contain code to load up messages from files. Not implemented yet. 2003-01-26 Havoc Pennington * dbus/dbus-message.c (dbus_message_set_sender): support deleting the sender by setting to NULL 2003-01-26 Havoc Pennington The unit tests pass, but otherwise untested. If it breaks, the tests should have been better. ;-) * bus/driver.c (bus_driver_handle_hello): return if we disconnect the connection. * dbus/dbus-message.c: redo everything so we maintain message->header as the only copy of the various fields. This avoids the possibility of out-of-memory in some cases, for example dbus_message_lock() can't run out of memory anymore, and avoids extra copying. Figured I may as well go ahead and do this since it was busted for dbus_message_lock to not return failure on OOM, and dbus_message_write_header was totally unchecked for OOM. Also fixed some random other bugs. * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): verify that strings are nul-terminated. Also, end_pos can be equal to string length just not greater than, I think. (_dbus_marshal_set_int32): new function (_dbus_marshal_set_uint32): new function (_dbus_marshal_set_string): new function * dbus/dbus-connection.c (_dbus_connection_new_for_transport): fix a warning, init timeout_list to NULL (dbus_connection_send_message): don't use uninitialized variable "serial" * dbus/dbus-string.c (_dbus_string_replace_len): new function 2003-01-26 Anders Carlsson * bus/driver.c: (bus_driver_handle_hello), (bus_driver_send_welcome_message): Plug leaks 2003-01-26 Anders Carlsson * dbus/dbus-auth.c: (process_auth), (_dbus_auth_unref): * dbus/dbus-connection.c: (_dbus_connection_new_for_transport), (dbus_connection_unref): * dbus/dbus-marshal.c: (_dbus_marshal_test): * dbus/dbus-message.c: (dbus_message_unref), Plug memory leaks. (dbus_message_get_fields): Remove debugging printout. (_dbus_message_loader_return_buffer): Don't store the header string. (_dbus_message_test): Plug leaks. 2003-01-26 Richard Hult * glib/dbus-gmain.c (dbus_connection_dispatch): Traverse a copy of the file descriptor list, since it can change under us. 2003-01-25 Anders Carlsson * glib/dbus-gmain.c: (dbus_connection_prepare), (dbus_connection_check), (dbus_connection_dispatch), (add_watch), (remove_watch), (dbus_connection_hookup_with_g_main): Rewrite the glib handling to use its own GSource instead of a GIOChannel so we can catch messages put in the queue while waiting for a reply. 2003-01-25 Anders Carlsson * bus/Makefile.am: * bus/connection.c: (connection_disconnect_handler), (connection_watch_callback), (bus_connection_setup): * bus/dispatch.c: (send_one_message), (bus_dispatch_broadcast_message), (bus_dispatch_message_handler), (bus_dispatch_add_connection), (bus_dispatch_remove_connection): * bus/dispatch.h: * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_handle_hello), (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_remove_connection), (bus_driver_handle_message): * bus/driver.h: Refactor code, put the message dispatching in its own file. Use _DBUS_HANDLE_OOM. Also send ServiceDeleted messages when a client is disconnected. 2003-01-25 Anders Carlsson * dbus/dbus-internals.h: Add _DBUS_HANDLE_OOM macro, it doesn't do anything currently. * dbus/dbus-message.c: (dbus_message_get_sender): * dbus/dbus-message.h: Implement dbus_message_get_sender. * dbus/dbus-protocol.h: Add message and service defines. 2003-01-25 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_client_serial), (dbus_message_write_header): Remove _dbus_messag_unlock and don't set the client serial on a message if one already exists. 2003-01-24 Havoc Pennington * dbus/dbus-list.c (alloc_link): put a thread lock on the global list_pool * bus/driver.c (bus_driver_handle_list_services): fix a leak on OOM 2003-01-25 Anders Carlsson * dbus/dbus-list.c: (alloc_link), (free_link): Use a memory pool for the links. 2003-01-25 Anders Carlsson * bus/connection.c: (bus_connection_foreach): * bus/connection.h: Add new bus_connection_foreach function. * bus/driver.c: (send_one_message), (bus_driver_broadcast_message): Add function that broadcasts a message to all clients. (bus_driver_send_service_created), (bus_driver_handle_hello), (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_message_handler): Implement functions that take care of listing services, and notifying clients when new services are created. * bus/services.c: (bus_services_list): * bus/services.h: Add new function that returns an array of strings with the currently registered services. * glib/dbus-glib.h: * glib/dbus-gmain.c: Update copyright year. 2003-01-25 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): Unlock the message in case it was sent earlier. (dbus_connection_send_message_with_reply_and_block): Remove the reply message from the list. * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): Set array_len and new_pos correctly. (_dbus_marshal_test): Remove debug output. * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_reply_serial): New function that returns the reply serial. (_dbus_message_unlock): New function that unlocks a message and resets its header. (dbus_message_append_string_array), (dbus_message_get_fields_valist), (dbus_message_iter_get_field_type), (dbus_message_iter_get_string_array), (dbus_message_get_fields), (dbus_message_append_fields_valist): Handle string arrays. (dbus_message_set_sender): Make this function public since the bus daemon needs it. (decode_header_data): Set the reply serial to -1 initially. * dbus/dbus-message.h: Add dbus_message_set_sender. 2003-01-24 Havoc Pennington * doc/dbus-specification.sgml: add some stuff 2003-01-22 Havoc Pennington * doc/dbus-specification.sgml: Start to document the protocol. 2003-01-22 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_send_message_with_reply_and_block): add some @todo * bus/driver.c (bus_driver_add_connection): add a FIXME about memleak 2003-01-21 Havoc Pennington (patch untested because can't compile) * bus/driver.c (create_unique_client_name): make this function never recycle client names. Also, caller should initialize the DBusString. * dbus/dbus-sysdeps.c (_dbus_get_current_time): new function 2003-01-21 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_double), (_dbus_marshal_int32), (_dbus_marshal_uint32), (_dbus_marshal_int32_array), (_dbus_marshal_uint32_array), (_dbus_marshal_double_array), (_dbus_marshal_string_array), (_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array), (_dbus_demarshal_double_array), (_dbus_demarshal_string_array), (_dbus_marshal_get_field_end_pos), (_dbus_marshal_test): * dbus/dbus-marshal.h: * dbus/dbus-protocol.h: Add support for marshalling and demarshalling integer, double and string arrays. 2003-01-21 Anders Carlsson * bus/Makefile.am: Add driver.[ch] * bus/connection.c: (connection_disconnect_handler): Remove the connection from the bus driver's list. (connection_watch_callback): Dispatch messages. (free_connection_data): Free connection name. (bus_connection_setup): Add connection to the bus driver's list. (bus_connection_remove_owned_service): (bus_connection_set_name), (bus_connection_get_name): Add functions for setting and getting the connection's name. * bus/connection.h: Add function headers. * bus/driver.c: (create_unique_client_name), (bus_driver_handle_hello_message), (bus_driver_send_welcome_message), (bus_driver_message_handler), (bus_driver_add_connection), (bus_driver_remove_connection): * bus/driver.h: * bus/main.c: * bus/services.c: (bus_service_free): * bus/services.h: New file that handles communication and registreation with the bus itself. 2003-01-21 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): Add a new client_serial parameter. (dbus_connection_send_message_with_reply): Remove a @todo since we've implemented the blocking function. (dbus_connection_send_message_with_reply_and_block): New function that sends a message and waits for a reply and then returns the reply. * dbus/dbus-connection.h: Add new functions. * dbus/dbus-errors.c: (dbus_result_to_string): * dbus/dbus-errors.h: Add new DBUS_RESULT. * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_reply_serial), (_dbus_message_set_sender), (dbus_message_write_header), (dbus_message_new_reply), (decode_header_data), (_dbus_message_loader_return_buffer), (_dbus_message_test): * dbus/dbus-message.h: Add new functions that set the reply serial and sender. Also marshal and demarshal them correctly and add test. * dbus/dbus-protocol.h: Add new DBUS_MESSAGE_TYPE_SENDER. * glib/dbus-glib.h: * glib/dbus-gmain.c: (watch_callback), (free_callback_data), (add_watch), (remove_watch), (add_timeout), (remove_timeout), (dbus_connection_hookup_with_g_main): * glib/test-dbus-glib.c: (main): Rewrite to use GIOChannel and remove the GSource crack. * test/echo-client.c: (main): * test/watch.c: (check_messages): Update for changed APIs 2003-01-19 Anders Carlsson * dbus/Makefile.am: Add dbus-timeout.[cħ] * dbus/dbus-connection.c: (_dbus_connection_new_for_transport): Create a DBusTimeoutList. (dbus_connection_set_timeout_functions): Add new function to set timeout callbacks * dbus/dbus-connection.h: Add public DBusTimeout API. * dbus/dbus-message.c: (dbus_message_get_service): * dbus/dbus-message.h: New function. * dbus/dbus-server.c: Fix small doc typo. * dbus/dbus-timeout.[ch]: New files for mainloop timeouts. 2003-01-19 Anders Carlsson * dbus/dbus-string.c (_dbus_string_move_len): Don't delete all of the string, just as long as specified. 2003-01-19 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_get_is_authenticated): new function * dbus/dbus-server.c (dbus_server_set_max_connections) (dbus_server_get_max_connections, dbus_server_get_n_connections): keep track of current number of connections, and add API for setting a max (but haven't implemented enforcing the max yet) 2003-01-18 Havoc Pennington * dbus/dbus-transport-unix.c (unix_do_iteration): only do the reading/writing if read_watch != NULL or write_watch != NULL. * dbus/dbus-message.c (_dbus_message_loader_return_buffer): fix the message loader code to actually load message->header and message->body into the newly-created message. * dbus/dbus-transport-unix.c (check_write_watch): fix a mem leak in OOM case * dbus/dbus-connection.c (dbus_connection_set_max_message_size) (dbus_connection_get_max_message_size) (dbus_connection_set_max_live_messages_size) (dbus_connection_get_max_live_messages_size): implement some resource limitation functions * dbus/dbus-resources.c: new file implementing some of the resource limits stuff * dbus/dbus-message.c (dbus_message_iter_get_byte_array): add missing docs, add @todo to handle OOM etc. * dbus/dbus-marshal.c (_dbus_demarshal_byte_array): add missing docs 2003-01-18 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_unref): disconnect the connection if it hasn't been already. * dbus/dbus-connection.h: kill off the idea of an ErrorFunction, replace with DisconnectFunction. 2003-01-18 Havoc Pennington Building --disable-verbose-mode --disable-asserts --disable-tests cuts the library from 112K to 45K or so * configure.in: check for varargs macro support, add --enable-verbose-mode, --enable-asserts. * dbus/dbus-internals.h (_dbus_assert): support DBUS_DISABLE_ASSERT (_dbus_verbose): support DBUS_ENABLE_VERBOSE_MODE 2003-01-18 Havoc Pennington * dbus/dbus-test.c: include config.h so that tests actually run * dbus/dbus-string.c: add assertions that stuff is 8-byte aligned, so the failure mode when that assumption fails will be plenty obvious. 2003-01-18 Havoc Pennington * configure.in: default --enable-tests to $USE_MAINTAINER_MODE * dbus/Makefile.am: fix it up so dubs-test-main.c is included in the distribution * test/Makefile.am: don't use special variable "TESTS" for echo-* since we don't want to use those in make check 2003-01-15 Havoc Pennington Release 0.2 * NEWS: update 2003-01-15 Havoc Pennington * test/Makefile.am: fix so that test source code ends up in the distribution on make distcheck 2003-01-15 Havoc Pennington Release 0.1. * NEWS: update 2003-01-15 Havoc Pennington * dbus/dbus-test.c (dbus_internal_symbol_do_not_use_run_tests): fix build when --disable-tests * Makefile.am (EXTRA_DIST): put HACKING in here * HACKING: document procedure for making a tarball release. 2003-01-14 Anders Carlsson * bus/connection.c: (connection_error_handler), (bus_connection_setup): * bus/main.c: (main): Make sure that the DBusConnectionData struct is NULLed out to prevent a segfault. * dbus/dbus-errors.c: (dbus_result_to_string): * dbus/dbus-errors.h: * dbus/dbus-message.c: (dbus_message_get_fields), (dbus_message_get_fields_valist), (_dbus_message_test): * dbus/dbus-message.h: Make dbus_message_get_fields return a result code so we can track invalid fields as well as oom. 2003-01-11 Havoc Pennington * configure.in: change --enable-test/--enable-ansi action-if-given to enable_foo=$enableval instead of enable_foo=yes 2003-01-08 Havoc Pennington * dbus/dbus-string.c (_dbus_string_align_length): new function * dbus/dbus-test-main.c: move main() for test app here * dbus/dbus-test.c (dbus_internal_symbol_do_not_use_run_tests): we have to export a symbol to run tests, because dbus-test isn't in the main library Code review nitpicks. * dbus/dbus-message.c (dbus_message_write_header): add newlines for people with narrow emacs ;-). Assert client_serial was filled in. Assert message->name != NULL. (dbus_message_append_fields): have "first_field_type" arg separate from va list, needed for C++ binding that also uses varargs IIRC and helps with type safety (dbus_message_new): add @todo about using DBusString to store service/name internally (dbus_message_new): don't leak ->service and ->name on OOM later in the function (dbus_message_unref): free the service name (dbus_message_get_fields): same change to varargs i.e. first_field_type (_dbus_message_loader_return_buffer): assert that the message data is aligned (if not it's a bug in our code). Put in verbose griping about why we set corrupted = TRUE. (decode_header_data): add FIXME that char* is evil. Was going to add FIXME about evil locale-specific string.h strncmp, but just switched to wacky string-as-uint32 optimization. Move check for "no room for field name" above get_const_data_len() to avoid assertion failure in get_const_data_len if we have trailing 2 bytes or the like. Check for service and name fields being provided twice. Don't leak service/name on error. Require field names to be aligned to 4 bytes. * dbus/dbus-marshal.c: move byte swap stuff to header (_dbus_pack_int32): uscore-prefix (_dbus_unpack_int32): uscore-prefix (_dbus_unpack_uint32): export (_dbus_demarshal_string): add @todo complaining about use of memcpy() (_dbus_marshal_get_field_end_pos): add @todo about bad error handling allowing corrupt data to go unchecked 2003-01-08 Havoc Pennington * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write to the select() as needed for authentication. (should be using _dbus_poll() not select, but for another day) * dbus/dbus.h: include dbus/dbus-protocol.h 2003-01-08 Anders Carlsson * dbus/Makefile.am (dbusinclude_HEADERS): Install dbus-connection.h 2003-01-08 Anders Carlsson * dbus/dbus-internals.c: (_dbus_type_to_string): New function that returns a string describing a type. * dbus/dbus-marshal.c: (_dbus_demarshal_byte_array): * dbus/dbus-marshal.h: * dbus/dbus-message.c: (dbus_message_get_fields_valist), (dbus_message_iter_get_field_type), (dbus_message_iter_get_double), (dbus_message_iter_get_byte_array): * dbus/dbus-message.h: Add new convenience functions for appending and getting message fields. Also add demarshalling routines for byte arrays. 2003-01-07 Anders Carlsson * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: (_dbus_connection_new_for_transport), (_dbus_connection_get_next_client_serial), (dbus_connection_send_message): * dbus/dbus-internals.h: * dbus/dbus-marshal.c: (unpack_uint32), (dbus_unpack_int32), (dbus_pack_int32), (_dbus_marshal_double), (_dbus_marshal_int32), (_dbus_marshal_uint32), (_dbus_demarshal_double), (_dbus_demarshal_int32), (_dbus_demarshal_uint32), (_dbus_demarshal_string), (_dbus_marshal_get_field_end_pos), (_dbus_verbose_bytes), (_dbus_marshal_test): * dbus/dbus-marshal.h: * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_set_client_serial), (dbus_message_write_header), (_dbus_message_lock), (dbus_message_new), (dbus_message_ref), (dbus_message_unref), (dbus_message_get_name), (dbus_message_append_int32), (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_byte_array), (dbus_message_get_fields_iter), (dbus_message_iter_ref), (dbus_message_iter_unref), (dbus_message_iter_has_next), (dbus_message_iter_next), (dbus_message_iter_get_field_type), (dbus_message_iter_get_string), (dbus_message_iter_get_int32), (dbus_message_iter_get_uint32), (dbus_message_iter_get_double), (decode_header_data), (_dbus_message_loader_return_buffer), (message_iter_test), (_dbus_message_test): * dbus/dbus-message.h: * dbus/dbus-protocol.h: * dbus/dbus-test.c: (main): * dbus/dbus-test.h: * glib/test-dbus-glib.c: (message_handler), (main): * test/echo-client.c: (main): * test/watch.c: (check_messages): Make messages sendable and receivable for real. 2003-01-07 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_double), (_dbus_marshal_string), (_dbus_marshal_byte_array): * dbus/dbus-message.c: (dbus_message_append_int32), (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_byte_array): Handle OOM restoration. 2003-01-07 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_string), (_dbus_demarshal_string), (_dbus_marshal_test): * dbus/dbus-marshal.h: * dbus/dbus-message.c: (dbus_message_get_name), Document these functions. (dbus_message_append_int32), (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_byte_array): * dbus/dbus-message.h: Add functions for adding message fields of different types. * dbus/dbus-protocol.h: Add the different types. 2003-01-05 Havoc Pennington * bus/connection.c: implement routines for handling connections, first thing is keeping a list of owned services on each connection and setting up watches etc. * bus/services.c: implement a mapping from service names to lists of connections * dbus/dbus-hash.c: add DBUS_HASH_POINTER * dbus/dbus-threads.c (dbus_static_mutex_lock): add functions to use static mutexes for global data * dbus/dbus-connection.c (dbus_connection_set_data): add new collection of functions to set/get application-specific data on the DBusConnection. 2003-01-04 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_sleep_milliseconds): new function (_dbus_poll): new function * dbus/dbus-internals.h (_DBUS_STRUCT_OFFSET): new macro copied from GLib * bus/loop.c: initial code for the daemon main loop 2003-01-04 Havoc Pennington * test/watch.c (error_handler): make it safe if the error handler is called multiple times (if we s/error handler/disconnect handler/ we should just guarantee it's called only once) * dbus/dbus-transport.c (_dbus_transport_disconnect): call the error handler on disconnect (it's quite possible we should just change the error handler to a "disconnect handler," I'm not sure we have any other meaningful errors) * configure.in: check for getpwnam_r * dbus/dbus-transport.c, dbus/dbus-transport-unix.c, dbus/dbus-auth.c: add credentials support, add EXTERNAL auth mechanism as in SASL spec, using socket credentials * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): new function (_dbus_send_credentials_unix_socket): new function * dbus/dbus-sysdeps.c (_dbus_accept_unix_socket): rename just dbus_accept() (_dbus_write): only check errno if <0 returned (_dbus_write_two): ditto 2003-01-02 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_utf8_string), (_dbus_marshal_byte_array), (_dbus_demarshal_utf8_string), (_dbus_marshal_test): * dbus/dbus-marshal.h: Add _dbus_marshal_byte_array and rename _dbus_marshal_string to _dbus_marshal_utf8_string. Also fix some tests. 2002-12-28 Harri Porten * configure.in: added check for C++ compiler and a very cheesy check for the Qt integration * Makefile.am (SUBDIRS): compile qt subdir if support is enabled * qt/Makefile.am: added * qt/.cvsignore: added * qt/dbus-qthread.cc, qt/dbus-qthread.cpp: renamed former to latter, added #ifdef QT_THREAD_SUPPORT guard. * dbus/Makefile.am: added missing headers for make dist 2002-12-28 Kristian Rietveld * dbus/Makefile.am: fixup export-symbols-regex. 2002-12-27 Anders Carlsson * acinclude.m4: Add this file and put the PKG_CHECK_MODULE macro in it. 2002-12-27 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_string), (_dbus_demarshal_double), (_dbus_demarshal_int32), (_dbus_demarshal_uint32), (_dbus_demarshal_string), (_dbus_marshal_test): Make the demarshalling routines align the pos argument. Add string marshalling tests and fix the obvious bugs discovered. 2002-12-26 Havoc Pennington * dbus/dbus-auth.c: fixes fixes fixes * dbus/dbus-transport-unix.c: wire up support for encoding/decoding data on the wire * dbus/dbus-auth.c (_dbus_auth_encode_data) (_dbus_auth_decode_data): append to target string instead of nuking it. 2002-12-26 Havoc Pennington * dbus/dbus-marshal.h (DBUS_COMPILER_BYTE_ORDER): #ifdef WORDS_BIGENDIAN then compiler byte order is DBUS_BIG_ENDIAN, doh * dbus/dbus-marshal.c: Add macros to do int swapping in-place and avoid swap_bytes() overhead (ignoring possible assembly stuff for now). Main point is because I wanted unpack_uint32 to implement _dbus_verbose_bytes (_dbus_verbose_bytes): new function * dbus/dbus-string.c (_dbus_string_validate_ascii): new function * dbus/dbus-message.c (_dbus_message_loader_get_is_corrupted): add mechanism to handle a corrupt message stream (_dbus_message_loader_new): fix preallocation to only prealloc, not prelengthen * dbus/dbus-string.c (_dbus_string_skip_blank): fix this function (_dbus_string_test): enhance tests for copy/move and fix the functions * dbus/dbus-transport-unix.c: Hold references in more places to avoid reentrancy problems * dbus/dbus-transport.c: ditto * dbus/dbus-connection.c (dbus_connection_dispatch_message): don't leak reference count in no-message case * test/watch.c (do_mainloop): handle adding/removing watches during iteration over the watches. Also, ref the connection/server stored on a watch, so we don't try to mangle a destroyed one. * dbus/dbus-transport-unix.c (do_authentication): perform authentication * dbus/dbus-auth.c (get_state): add a state AUTHENTICATED_WITH_UNUSED_BYTES and return it if required (_dbus_auth_get_unused_bytes): append the unused bytes to the passed in string, rather than prepend * dbus/dbus-transport.c (_dbus_transport_init_base): create the auth conversation DBusAuth * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd) (_dbus_transport_new_for_domain_socket): when creating a transport, pass in whether it's a client-side or server-side transport so we know which DBusAuth to create 2002-12-03 Havoc Pennington * dbus/dbus-transport-unix.c (unix_finalize): finalize base _after_ finalizing the derived members (unix_connection_set): unref watch if we fail to add it * dbus/dbus-connection.c (dbus_connection_unref): delete the transport first, so that the connection owned by the transport will be valid as the transport finalizes. * dbus/dbus-transport-unix.c (unix_finalize): free the write_watch if necessary, and remove watches from the connection. * dbus/dbus-watch.c (_dbus_watch_list_free): improve a comment 2002-12-26 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_string), (_dbus_demarshal_double), (_dbus_demarshal_int32), (_dbus_demarshal_uint32), (_dbus_demarshal_string), (_dbus_marshal_test): * dbus/dbus-marshal.h: Add string marshal functions and have the demarshal functions return the new position. 2002-12-25 Havoc Pennington * doc/dbus-sasl-profile.txt: docs on the authentication protocol, it is a simple protocol that just maps directly to SASL. * dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol initial implementation, not actually used yet. * dbus/dbus-string.c (_dbus_string_find): new function (_dbus_string_equal): new function (_dbus_string_base64_encode): new function (_dbus_string_base64_decode): new function 2002-12-25 Anders Carlsson * dbus/Makefile.am: * dbus/dbus-marshal.c: (swap_bytes), (_dbus_marshal_double), (_dbus_marshal_int32), (_dbus_marshal_uint32), (_dbus_demarshal_double), (_dbus_demarshal_int32), (_dbus_demarshal_uint32), (_dbus_marshal_test): * dbus/dbus-marshal.h: * dbus/dbus-protocol.h: * dbus/dbus-test.c: (main): * dbus/dbus-test.h: Add un-optimized marshalling/demarshalling routines. 2002-12-25 Harri Porten * qt/dbus-qt.h: adjusted ctor and getter to KDE/Qt conventions 2002-12-24 Zack Rusin * qt/dbus-qthread.cc: adding - integrates QMutex into Dbus * qt/dbus-qt.h: skeleton with two sample implemenatation of the main loop stuff 2002-12-24 Havoc Pennington * glib/dbus-gthread.c: fix include * glib/dbus-glib.h: rename DBusMessageHandler for now. I think glib API needs to change, though, as you don't want to use DBusMessageFunction, you want to use the DBusMessageHandler object. Probably dbus_connection_open_with_g_main_loop() and dbus_connection_setup_g_main_loop() or something like that (but think of better names...) that just create a connection that has watch/timeout functions etc. already set up. * dbus/dbus-connection.c (dbus_connection_send_message_with_reply): new function just to show how the message handler helps us deal with replies. * dbus/dbus-list.c (_dbus_list_remove_last): new function * dbus/dbus-string.c (_dbus_string_test): free a string that wasn't * dbus/dbus-hash.c: use memory pools for the hash entries (rebuild_table): be more paranoid about overflow, and shrink table when we can (_dbus_hash_test): reduce number of sprintfs and write valid C89. Add tests for case where we grow and then shrink the hash table. * dbus/dbus-mempool.h, dbus/dbus-mempool.c: memory pools * dbus/dbus-connection.c (dbus_connection_register_handler) (dbus_connection_unregister_handler): new functions * dbus/dbus-message.c (dbus_message_get_name): new * dbus/dbus-list.c: fix docs typo * dbus/dbus-message-handler.h, dbus/dbus-message-handler.c: an object representing a handler for messages. 2002-12-16 Anders Carlsson * glib/dbus-glib.h: * glib/dbus-gthread.c: (dbus_gthread_init): Don't use the gdbus prefix for public functions. 2002-12-16 Anders Carlsson * Makefile.am: * configure.in: Add GLib checks and fixup .pc files * glib/Makefile.am: * glib/dbus-glib.h: * glib/dbus-gmain.c: (gdbus_connection_prepare), (gdbus_connection_check), (gdbus_connection_dispatch), (gdbus_add_connection_watch), (gdbus_remove_connection_watch), (dbus_connection_gsource_new): * glib/dbus-gthread.c: (dbus_gmutex_new), (dbus_gmutex_free), (dbus_gmutex_lock), (dbus_gmutex_unlock), (dbus_gthread_init): * glib/test-dbus-glib.c: (message_handler), (main): Add GLib support. 2002-12-15 Harri Porten * autogen.sh: check for libtoolize before attempting to use it * dbus/dbus-transport-unix.c: include for timeval struct. * .cvsignore: ignore more stamp files * dbus/dbus-watch.c (_dbus_watch_list_new): fixed doc error * test/Makefile.am: added -I$(top_srcdir) to be able to compile without make install. 2002-12-15 Havoc Pennington * dbus/dbus-threads.c: add thread stubs that a higher library layer can fill in. e.g. the GLib wrapper might fill them in with GThread stuff. We still need to use this thread API to thread-safe-ize the library. 2002-12-12 Havoc Pennington * dbus/dbus-transport-unix.c, dbus/dbus-server-unix.c: use the below new interfaces and include fewer system headers. * dbus/dbus-sysdeps.c (_dbus_read): new function (_dbus_write): new function (_dbus_write_two): new function (_dbus_connect_unix_socket): new function (_dbus_listen_unix_socket): new function * dbus/dbus-message-internal.h: change interfaces to use DBusString 2002-12-11 Havoc Pennington * dbus/dbus-types.h: add dbus_unichar * dbus/dbus-internals.c (_dbus_verbose): use _dbus_getenv * dbus/dbus-connection.c (dbus_connection_send_message): return TRUE on success * dbus/dbus-transport.c: include dbus-watch.h * dbus/dbus-connection.c: include dbus-message-internal.h * HACKING: add file with coding guidelines stuff. * dbus/dbus-string.h, dbus/dbus-string.c: Encapsulate all string handling here, for security purposes (as in vsftpd). Not actually using this class yet. * dbus/dbus-sysdeps.h, dbus/dbus-sysdeps.c: Encapsulate all system/libc usage here, as in vsftpd, for ease of auditing (and should also simplify portability). Haven't actually moved all the system/libc usage into here yet. 2002-11-25 Havoc Pennington * dbus/dbus-internals.c (_dbus_verbose): fix to not always print the first verbose message. 2002-11-24 Havoc Pennington * test/echo-client.c, test/echo-server.c: cheesy test clients. * configure.in (AC_CHECK_FUNCS): check for writev * dbus/dbus-message.c (_dbus_message_get_network_data): new function * dbus/dbus-list.c (_dbus_list_foreach): new function * dbus/dbus-internals.c (_dbus_verbose): new function * dbus/dbus-server.c, dbus/dbus-server.h: public object representing a server that listens for connections. * dbus/.cvsignore: create * dbus/dbus-errors.h, dbus/dbus-errors.c: public API for reporting errors * dbus/dbus-connection.h, dbus/dbus-connection.c: public object representing a connection that sends/receives messages. (Same object used for both client and server.) * dbus/dbus-transport.h, dbus/dbus-transport.c: Basic abstraction for different kinds of stream that we might read/write messages from. 2002-11-23 Havoc Pennington * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN _DBUS_INT_MAX * dbus/dbus-test.c (main): add list test, and include dbus-test.h as intended * dbus/dbus-hash.c (_dbus_hash_table_remove_string) (_dbus_hash_table_remove_int): return value indicates whether the entry existed to remove * dbus/dbus-list.c: add linked list utility class, with docs and tests * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket array sometimes. 2002-11-23 Havoc Pennington * Doxyfile.in (INCLUDE_FILE_PATTERNS): expand DBUS_BEGIN_DECLS/ DBUS_END_DECLS to nothing, that should fix this once and for all * Doxyfile.in (JAVADOC_AUTOBRIEF): set to YES * dbus/dbus-message.c, dbus/dbus-hash.c: add some missing @brief 2002-11-23 Havoc Pennington * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS to avoid confusing Doxygen * dbus/dbus-hash.c: @} not }@ * dbus/dbus-message.c (struct DBusMessage): split out internals docs 2002-11-23 Havoc Pennington * configure.in: pile on more warning flags if using gcc * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have to document static functions * configure.in: add summary to end of configure so it looks nice and attractive * dbus/dbus-hash.c: finish implementation and write unit tests and docs * configure.in: add --enable-tests to enable unit tests * dbus/dbus-test.c: test program to run unit tests for all files in dbus/*, initially runs a test for dbus-hash.c * dbus/dbus-internals.h: file to hold some internal utility stuff 2002-11-22 Havoc Pennington * dbus/dbus-hash.c: copy in Tcl hash table, not yet "ported" away from Tcl * dbus/dbus-types.h: header for types such as dbus_bool_t 2002-11-22 Havoc Pennington * dbus/dbus.h: fixups for doc warnings * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up macros (QUIET): make it quiet so we can see warnings * dbus/dbus-memory.c: teach D-BUS to allocate and free memory 2002-11-22 Havoc Pennington * Makefile.am: include "Doxyfile" target in all-local * configure.in: generate the Doxyfile * Doxyfile.in: move Doxyfile here, so we can use configure to generate a Doxyfile with the right version number etc. 2002-11-22 Havoc Pennington * dbus/dbus-message.c: move inline docs into .c file * Doxyfile (OUTPUT_DIRECTORY): move output to doc/api so all docs are under doc/ (MAN_EXTENSION): generate man pages. Use extension ".3dbus" which matches ".3qt" on my system, I guess this is OK, I don't know really. (FILE_PATTERNS): look for .c files not .h, makes sense for plain C I think 2002-11-22 Havoc Pennington * Makefile.am (SUBDIRS): rename subdir "server" to "bus" because any app can be a server, and any app can be a client, the bus is a special kind of server. Thu Nov 21 23:35:31 2002 Zack Rusin * Doxyfile : adding. Still needs Makefile rules to be generated automatically (just run "doxygen" in the toplevel dir for now to generate docs) * dbus/dbus-message.h : Adding sample docs (javadoc since resembles gtk-doc a little more) * dbus/dbus.h : Adding sample docs 2002-11-21 Havoc Pennington * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION so we can allow ourselves to include files directly, instead of having to use dbus.h * dbus/dbus.h: fill in * dbus/dbus-message.h: sketch out a sample header file. Include griping if you include it directly instead of via dbus.h * dbus/dbus-macros.h: new file with macros for extern "C", TRUE/FALSE, NULL, etc. * doc/file-boilerplate.c: put include guards in here 2002-11-21 Havoc Pennington * doc/file-boilerplate.c: include both AFL and GPL boilerplate. * COPYING: include the GPL as well, and license code under both AFL and GPL. 2002-11-21 Havoc Pennington * acconfig.h: get rid of this * autogen.sh (run_configure): add --no-configure option * configure.in: remove AC_ARG_PROGRAM to make autoconf complain less. add AC_PREREQ. add AC_DEFINE third arg. 2002-11-21 Anders Carlsson * doc/Makefile.am: Fix references so we can distcheck. 2002-11-21 Havoc Pennington * Initial module creation dbus-1.10.6/cleanup-man-pages.sh0000755000175000017500000000751112602773110016375 0ustar00smcvsmcv00000000000000#! /bin/sh ## This script cleans up private/internal API from the man pages ## generated by Doxygen. This brings the man pages down from 7 megs ## to 2 megs and avoids namespace-polluting man pages. It's probably ## pretty specific to GNU utilities. Patches gladly accepted to make ## it work without them. ## You would run this after building dbus and after running "doxygen ## Doxyfile" die() { echo "$*" 1>&2 exit 1 } MANDIR=$1 if test x"$MANDIR" = x ; then MANDIR=doc/api/man/man3dbus fi cd "$MANDIR" || die "Could not cd to $MANDIR" test -d keep || mkdir keep || die "Could not create $MANDIR/keep directory" test -d nuke || mkdir nuke || die "Could not create $MANDIR/nuke directory" ## blacklist (find . -maxdepth 1 -name "_*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all underscore-prefixed items" (find . -maxdepth 1 -name "DBus*Internal*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all internal-containing items" (find . -maxdepth 1 -name "dbus_*_internal_*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all internal-containing items" ## this is kind of unmaintainable, but I guess it's no huge disaster if we miss something. ## this list should only contain man pages with >1 line, i.e. with real content; the ## one-line cross-references get cleaned up next. for I in DBusCounter.* DBusCredentials.* DBusDataSlot.* DBusDataSlotAllocator.* DBusDataSlotList.* \ DBusDirIter.* DBusFakeMutex.* DBusFreedElement.* DBusGroupInfo.* DBusGUID.* DBusHashEntry.* \ DBusHashIter.* DBusHashTable.* DBusHeader.* DBusHeaderField.* DBusKey.* DBusKeyring.* DBusList.* \ DBusMarshal.* DBusMD5* DBusMemBlock.* DBusMemPool.* DBusMessageGenerator.* DBusMessageLoader.* \ DBusMessageRealIter.* DBusObjectSubtree.* DBusObjectTree.* DBusPollFD.* DBusReal* \ DBusResources.* DBusServerDebugPipe.* DBusServerSocket.* DBusServerUnix.* \ DBusServerVTable.* DBusSHA.* DBusSHAContext.* DBusSignatureRealIter.* DBusStat.* DBusString.* \ DBusSysdeps.* DBusSysdepsUnix.* DBusTimeoutList.* DBusTransport* DBusTypeReader* DBusTypeWriter* \ DBusUserInfo.* DBusWatchList.* ; do if test -f "$I" ; then /bin/mv "$I" nuke || die "could not move $I to $MANDIR/nuke" fi done ## many files just contain ".so man3dbus/DBusStringInternals.3dbus" or the like, ## if these point to something we nuked, we want to also nuke the pointer. for I in * ; do if test -f "$I" ; then LINES=`wc -l "$I" | cut -d ' ' -f 1` if test x"$LINES" = x1 ; then REF_TO=`cat "$I" | sed -e 's/\.so man3dbus\///g'` ## echo "$I points to $REF_TO" if ! test -f "$REF_TO" ; then /bin/mv "$I" nuke || die "could not move $I to $MANDIR/nuke" fi fi fi done ## whitelist (find . -maxdepth 1 -name "dbus_*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all dbus-prefixed items" (find . -maxdepth 1 -name "DBUS_*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all DBUS_-prefixed items" (find . -maxdepth 1 -name "DBus*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all DBus-prefixed items" ## everything else is assumed irrelevant, this is mostly struct fields ## from the public headers (find . -maxdepth 1 -type f | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move remaining items" NUKE_COUNT=`find nuke -type f -name "*" | wc -l` KEEP_COUNT=`find keep -type f -name "*" | wc -l` MISSING_COUNT=`find . -maxdepth 1 -type f -name "*" | wc -l` echo "$KEEP_COUNT man pages kept and $NUKE_COUNT man pages to remove" echo "$MISSING_COUNT not handled" (find keep -type f -name "*" | xargs -I ITEMS /bin/mv ITEMS .) || die "could not move kept items back" rmdir keep || die "could not remove $MANDIR/keep" echo "Man pages to be installed are in $MANDIR and man pages to ignore are in $MANDIR/nuke" exit 0 dbus-1.10.6/HACKING0000644000175000017500000003237612602773110013537 0ustar00smcvsmcv00000000000000The guidelines in this file are the ideals; it's better to send a not-fully-following-guidelines patch than no patch at all, though. We can always polish it up. Mailing list === The D-Bus mailing list is dbus@lists.freedesktop.org; discussion of patches, etc. should go there. Security === If you find a security vulnerability that is not known to the public, please report it privately to dbus-security@lists.freedesktop.org or by reporting a freedesktop.org bug that is marked as restricted to the "D-BUS security group". Most of D-Bus is security sensitive. Guidelines related to that: - avoid memcpy(), sprintf(), strlen(), snprintf, strlcat(), strstr(), strtok(), or any of this stuff. Use DBusString. If DBusString doesn't have the feature you need, add it to DBusString. There are some exceptions, for example if your strings are just used to index a hash table and you don't do any parsing/modification of them, perhaps DBusString is wasteful and wouldn't help much. But definitely if you're doing any parsing, reallocation, etc. use DBusString. - do not include system headers outside of dbus-memory.c, dbus-sysdeps.c, and other places where they are already included. This gives us one place to audit all external dependencies on features in libc, etc. - do not use libc features that are "complicated" and may contain security holes. For example, you probably shouldn't try to use regcomp() to compile an untrusted regular expression. Regular expressions are just too complicated, and there are many different libc's out there. - we need to design the message bus daemon (and any similar features) to use limited privileges, run in a chroot jail, and so on. http://vsftpd.beasts.org/ has other good security suggestions. Coding Style === - The C library uses GNU coding conventions, with GLib-like extensions (e.g. lining up function arguments). The Qt wrapper uses KDE coding conventions. - Write docs for all non-static functions and structs and so on. try "doxygen Doxyfile" prior to commit and be sure there are no warnings printed. - All external interfaces (network protocols, file formats, etc.) should have documented specifications sufficient to allow an alternative implementation to be written. Our implementation should be strict about specification compliance (should not for example heuristically parse a file and accept not-well-formed data). Avoiding heuristics is also important for security reasons; if it looks funny, ignore it (or exit, or disconnect). Development === D-Bus uses Git as its version control system. The main repository is hosted at git.freedesktop.org/dbus/dbus. To clone D-Bus, execute the following command: git clone git://git.freedesktop.org/dbus/dbus OR git clone git.freedesktop.org:dbus/dbus The latter form is the one that allows pushing, but it also requires an SSH account on the server. The former form allows anonymous checkouts. D-Bus development happens in two branches in parallel: the current stable branch, with an even minor number (like 1.0, 1.2 and 1.4), and the next development branch, with the next odd number. The stable branch is named after the version number itself (dbus-1.2, dbus-1.4), whereas the development branch is simply known as "master". When making a change to D-Bus, do the following: - check out the earliest branch of D-Bus that makes sense to have your change in. If it's a bugfix, it's normally the current stable branch; if it's a feature, it's normally the "master" branch. If you have an important security fix, you may want to apply to older branches too. - for large changes: if you're developing a new, large feature, it's recommended to create a new branch and do your development there. Publish your branch at a suitable place and ask others to help you develop and test it. Once your feature is considered finalised, you may merge it into the "master" branch. - for small changes: . make your change to the source code . execute tests to guarantee that you're not introducing a regression. For that, execute: make check (if possible, add a new test to check the fix you're introducing) . commit your change using "git commit" in the commit message, write a short sentence describing what you did in the first line. Then write a longer description in the next paragraph(s). . repeat the previous steps if necessary to have multiple commits - extract your patches and send to the D-Bus mailing list for review or post them to the D-Bus Bugzilla, attaching them to a bug report. To extract the patches, execute: git format-patch origin/master - once your code has been reviewed, you may push it to the Git server: git push origin my-branch:remote OR git push origin dbus-X.Y OR git push origin master (consult the Git manual to know which command applies) - (Optional) if you've not worked on "master", merge your changes to that branch. If you've worked on an earlier branch than the current stable, merge your changes upwards towards the stable branch, then from there into "master". . execute: git checkout master . ensure that you have the latest "master" from the server, update if you don't . execute: git merge dbus-X.Y . if you have any conflicts, resolve them, git add the conflicted files and then git commit . push the "master" branch to the server as well Executing this merge is recommended, but not necessary for all changes. You should do this step if your bugfix is critical for the development in "master", or if you suspect that conflicts will arise (you're usually the best person to resolve conflicts introduced by your own code), or if it has been too long since the last merge. Making a release === To make a release of D-Bus, do the following: - check out a fresh copy from Git - verify that the libtool versioning/library soname is changed if it needs to be, or not changed if not - update the file NEWS based on the git history - verify that the version number of dbus-specification.xml is changed if it needs to be; if changes have been made, update the release date in that file - update the AUTHORS file with "make update-authors" if necessary - the version number should have major.minor.micro, even if micro is 0, i.e. "1.0.0" and "1.2.0" not "1.0"/"1.2"; the micro version should be even for releases, and odd for intermediate snapshots - "make distcheck" (DO NOT just "make dist" - pass the check!) - if make distcheck fails, fix it. - once distcheck succeeds, "git commit -a". This is the version of the tree that corresponds exactly to the released tarball. - tag the tree with "git tag -s -m 'Released X.Y.Z' dbus-X.Y.Z" where X.Y.Z is the version of the release. If you can't sign then simply created an unsigned annotated tag: "git tag -a -m 'Released X.Y.Z' dbus-X.Y.Z". - bump the version number up in configure.ac (so the micro version is odd), and commit it. Make sure you do this *after* tagging the previous release! The idea is that git has a newer version number than anything released. Similarly, bump the version number of dbus-specification.xml and set the release date to "(not finalized)". - merge the branch you've released to the chronologically-later branch (usually "master"). You'll probably have to fix a merge conflict in configure.ac (the version number). - push your changes and the tag to the central repository with git push origin master dbus-X.Y dbus-X.Y.Z - scp your tarball to freedesktop.org server and copy it to dbus.freedesktop.org:/srv/dbus.freedesktop.org/www/releases/dbus/dbus-X.Y.Z.tar.gz. This should be possible if you're in group "dbus" - Update the online documentation with `make -C doc maintainer-upload-docs`. - update the wiki page http://www.freedesktop.org/Software/dbus by adding the new release under the Download heading. Then, cut the link and changelog for the previous that was there. - update the wiki page http://www.freedesktop.org/Software/DbusReleaseArchive pasting the previous release. Note that bullet points for each of the changelog items must be indented three more spaces to conform to the formatting of the other releases there. - post to dbus@lists.freedesktop.org announcing the release. Making a ".0" stable release === We create a branch for each stable release. The branch name should be dbus-X.Y which is a branch that has releases versioned X.Y.Z; changes on a stable branch should be limited to significant bug fixes. Because we won't make minor changes like keeping up with the latest deprecations on a stable branch, stable branches should turn off the gcc warning for deprecated declarations (e.g. see commit 4ebb275ab7). Be extra-careful not to merge master (or any branch based on master) into a stable branch. To branch: git branch dbus-X.Y and upload the branch tag to the server: git push origin dbus-X.Y To develop in this branch: git checkout dbus-X.Y Environment variables === These are the environment variables that are used by the D-Bus client library DBUS_VERBOSE=1 Turns on printing verbose messages. This only works if D-Bus has been compiled with --enable-verbose-mode DBUS_MALLOC_FAIL_NTH=n Can be set to a number, causing every nth call to dbus_alloc or dbus_realloc to fail. This only works if D-Bus has been compiled with --enable-tests. DBUS_MALLOC_FAIL_GREATER_THAN=n Can be set to a number, causing every call to dbus_alloc or dbus_realloc to fail if the number of bytes to be allocated is greater than the specified number. This only works if D-Bus has been compiled with --enable-tests. DBUS_TEST_MALLOC_FAILURES=n Many of the D-Bus tests will run over and over, once for each malloc involved in the test. Each run will fail a different malloc, plus some number of mallocs following that malloc (because a fair number of bugs only happen if two or more mallocs fail in a row, e.g. error recovery that itself involves malloc). This env variable sets the number of mallocs to fail. Here's why you care: If set to 0, then the malloc checking is skipped, which makes the test suite a heck of a lot faster. Just run with this env variable unset before you commit. Tests === These are the test programs that are built if dbus is compiled using --enable-tests. dbus/test-dbus This is the main unit test program that tests all aspects of the D-Bus client library. dbus/bus-test This it the unit test program for the message bus. test/break-loader A test that tries to break the message loader by passing it randomly created invalid messages. test/name-test/* This is a suite of programs which are run with a temporary session bus. If your test involves multiple processes communicating, your best bet is to add a test in here. "make check" runs all the deterministic test programs (i.e. not break-loader). "make lcov-check" is available if you configure with --enable-compiler-coverage and gives a complete report on test suite coverage. Patches === Please file them at http://bugzilla.freedesktop.org under component dbus, and also post to the mailing list for discussion. The commit rules are: - for fixes that don't affect API or protocol, they can be committed if any one qualified reviewer other than patch author reviews and approves - for fixes that do affect API or protocol, two people in the reviewer group have to review and approve the commit, and posting to the list is definitely mandatory - if there's a live unresolved controversy about a change, don't commit it while the argument is still raging. - at their discretion, members of the reviewer group may also commit branches/patches under these conditions: - the branch does not add or change API, ABI or wire-protocol - the branch solves a known problem and is covered by the regression tests - there are no objections from the rest of the review group within a week of the patches being attached to Bugzilla - the committer gets a positive review on Bugzilla from someone they consider qualified to review the change (e.g. a colleague with D-Bus experience; not necessarily a member of the reviewer group) - regardless of reviews, to commit a patch: - make check must pass - the test suite must be extended to cover the new code as much as reasonably feasible (see Tests above) - the patch has to follow the portability, security, and style guidelines - the patch should as much as reasonable do one thing, not many unrelated changes No reviewer should approve a patch without these attributes, and failure on these points is grounds for reverting the patch. The reviewer group that can approve patches: Havoc Pennington Michael Meeks Alexander Larsson Zack Rusin Joe Shaw Mikael Hallendal Richard Hult Owen Fraser-Green Olivier Andrieu Colin Walters Thiago Macieira John Palmieri Scott James Remnant Will Thompson Simon McVittie David Zeuthen dbus-1.10.6/autogen.sh0000755000175000017500000000463212602773110014543 0ustar00smcvsmcv00000000000000#!/bin/sh # Run this to generate all the initial makefiles, etc. srcdir=`dirname $0` test -z "$srcdir" && srcdir=. ORIGDIR=`pwd` cd $srcdir PROJECT=dbus TEST_TYPE=-f FILE=dbus-1.pc.in DIE=0 if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then echo "Activating pre-commit hook." cp .git/hooks/pre-commit.sample .git/hooks/pre-commit chmod +x .git/hooks/pre-commit fi (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have autoconf installed to compile $PROJECT." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" DIE=1 } # If the user hasn't explicitly chosen an Automake version, use 1.11. This is # the earliest version that gives us silent rules. if test -z "$AUTOMAKE"; then AUTOMAKE=automake-1.11 ACLOCAL=aclocal-1.11 fi ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || { AUTOMAKE=automake ACLOCAL=aclocal } ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have automake installed to compile $PROJECT." echo "Get ftp://ftp.cygnus.com/pub/home/tromey/automake-1.2d.tar.gz" echo "(or a newer version if it is available)" DIE=1 } LIBTOOLIZE=`which libtoolize` if ! test -f "$LIBTOOLIZE"; then LIBTOOLIZE=`which glibtoolize` fi ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have libtoolize installed to compile $PROJECT." echo "Install the libtool package from ftp.gnu.org or a mirror." DIE=1 } if test "$DIE" -eq 1; then exit 1 fi test $TEST_TYPE $FILE || { echo "You must run this script in the top-level $PROJECT directory" exit 1 } if test -z "$*"; then echo "I am going to run ./configure with no arguments - if you wish " echo "to pass any to it, please specify them on the $0 command line." fi $LIBTOOLIZE --copy --force $ACLOCAL -I m4 $ACLOCAL_FLAGS ## optionally feature autoheader (autoheader --version) < /dev/null > /dev/null 2>&1 && autoheader $AUTOMAKE -a $am_opt autoconf || echo "autoconf failed - version 2.5x is probably required" cd $ORIGDIR if test x"$NOCONFIGURE" = x; then run_configure=true for arg in $*; do case $arg in --no-configure) run_configure=false ;; *) ;; esac done else run_configure=false fi if $run_configure; then $srcdir/configure --enable-developer --config-cache "$@" fi dbus-1.10.6/README0000644000175000017500000001607212602773110013423 0ustar00smcvsmcv00000000000000Sections in this file describe: - introduction and overview - low-level vs. high-level API - version numbers - options to the configure script - ABI stability policy Introduction === D-Bus is a simple system for interprocess communication and coordination. The "and coordination" part is important; D-Bus provides a bus daemon that does things like: - notify applications when other apps exit - start services on demand - support single-instance applications See http://www.freedesktop.org/software/dbus/ for lots of documentation, mailing lists, etc. See also the file HACKING for notes of interest to developers working on D-Bus. If you're considering D-Bus for use in a project, you should be aware that D-Bus was designed for a couple of specific use cases, a "system bus" and a "desktop session bus." These are documented in more detail in the D-Bus specification and FAQ available on the web site. If your use-case isn't one of these, D-Bus may still be useful, but only by accident; so you should evaluate carefully whether D-Bus makes sense for your project. Security == If you find a security vulnerability that is not known to the public, please report it privately to dbus-security@lists.freedesktop.org or by reporting a freedesktop.org bug that is marked as restricted to the "D-BUS security group" (you might need to "Show Advanced Fields" to have that option). On Unix systems, the system bus (dbus-daemon --system) is designed to be a security boundary between users with different privileges. On Unix systems, the session bus (dbus-daemon --session) is designed to be used by a single user, and only accessible by that user. We do not currently consider D-Bus on Windows to be security-supported, and we do not recommend allowing untrusted users to access Windows D-Bus via TCP. Note: low-level API vs. high-level binding APIs === A core concept of the D-Bus implementation is that "libdbus" is intended to be a low-level API. Most programmers are intended to use the bindings to GLib, Qt, Python, Mono, Java, or whatever. These bindings have varying levels of completeness and are maintained as separate projects from the main D-Bus package. The main D-Bus package contains the low-level libdbus, the bus daemon, and a few command-line tools such as dbus-launch. If you use the low-level API directly, you're signing up for some pain. Think of the low-level API as analogous to Xlib or GDI, and the high-level API as analogous to Qt/GTK+/HTML. Version numbers === D-Bus uses the common "Linux kernel" versioning system, where even-numbered minor versions are stable and odd-numbered minor versions are development snapshots. So for example, development snapshots: 1.1.1, 1.1.2, 1.1.3, 1.3.4 Stable versions: 1.0, 1.0.1, 1.0.2, 1.2.1, 1.2.3 All pre-1.0 versions were development snapshots. Development snapshots make no ABI stability guarantees for new ABI introduced since the last stable release. Development snapshots are likely to have more bugs than stable releases, obviously. Configuration === dbus could be build by using autotools or cmake. When using autotools the configure step is initiated by running ./configure with or without additional configuration flags. dbus requires GNU Make (on BSD systems, this is typically called gmake) or a "make" implementation with compatible extensions. When using cmake the configure step is initiated by running the cmake program with or without additional configuration flags. Configuration flags === When using autotools, run "./configure --help" to see the possible configuration options and environment variables. When using cmake, inspect README.cmake to see the possible configuration options and environment variables. API/ABI Policy === Now that D-Bus has reached version 1.0, the objective is that all applications dynamically linked to libdbus will continue working indefinitely with the most recent system and session bus daemons. - The protocol will never be broken again; any message bus should work with any client forever. However, extensions are possible where the protocol is extensible. - If the library API is modified incompatibly, we will rename it as in http://ometer.com/parallel.html - in other words, it will always be possible to compile against and use the older API, and apps will always get the API they expect. Interfaces can and probably will be _added_. This means both new functions and types in libdbus, and new methods exported to applications by the bus daemon. The above policy is intended to make D-Bus as API-stable as other widely-used libraries (such as GTK+, Qt, Xlib, or your favorite example). If you have questions or concerns they are very welcome on the D-Bus mailing list. NOTE ABOUT DEVELOPMENT SNAPSHOTS AND VERSIONING Odd-numbered minor releases (1.1.x, 1.3.x, 2.1.x, etc. - major.minor.micro) are devel snapshots for testing, and any new ABI they introduce relative to the last stable version is subject to change during the development cycle. Any ABI found in a stable release, however, is frozen. ABI will not be added in a stable series if we can help it. i.e. the ABI of 1.2.0 and 1.2.5 you can expect to be the same, while the ABI of 1.4.x may add more stuff not found in 1.2.x. NOTE ABOUT STATIC LINKING We are not yet firmly freezing all runtime dependencies of the libdbus library. For example, the library may read certain files as part of its implementation, and these files may move around between versions. As a result, we don't yet recommend statically linking to libdbus. Also, reimplementations of the protocol from scratch might have to work to stay in sync with how libdbus behaves. To lock things down and declare static linking and reimplementation to be safe, we'd like to see all the internal dependencies of libdbus (for example, files read) well-documented in the specification, and we'd like to have a high degree of confidence that these dependencies are supportable over the long term and extensible where required. NOTE ABOUT HIGH-LEVEL BINDINGS Note that the high-level bindings are _separate projects_ from the main D-Bus package, and have their own release cycles, levels of maturity, and ABI stability policies. Please consult the documentation for your binding. Bootstrapping D-Bus on new platforms === A full build of D-Bus, with all regression tests enabled and run, has some dependencies which themselves depend on D-Bus, either for compilation or for some of *their* regression tests: GLib, dbus-glib and dbus-python are currently affected. To avoid circular dependencies, when bootstrapping D-Bus for the first time on a new OS or CPU architecture, you can either cross-compile some of those components, or choose the build order and options carefully: * build and install D-Bus without tests - do not use the --enable-modular-tests=yes configure option - do not use the --enable-tests=yes configure option * build and install GLib, again without tests * use those versions of libdbus and GLib to build and install dbus-glib * ... and use those to install dbus-python * rebuild libdbus; this time you can run all of the tests * rebuild GLib; this time you can run all of the tests dbus-1.10.6/NEWS0000644000175000017500000022754512627362207013263 0ustar00smcvsmcv00000000000000D-Bus 1.10.6 (2015-12-01) == The “marzipan beetles” release. Fixes: • On Unix when running tests as root, don't assert that root and the dbus-daemon user can still call UpdateActivationEnvironment; assert that those privileged users can call BecomeMonitor instead (fd.o #93036, Simon McVittie) • On Windows, fix a memory leak in the autolaunch transport (fd.o #92899, Simon McVittie) • On Windows Autotools builds, don't run tests that rely on dbus-run-session and other Unix-specifics (fd.o #92899, Simon McVittie) D-Bus 1.10.4 (2015-11-17) == The “Frostburn Canyon” release. Enhancements: • GetConnectionCredentials, GetConnectionUnixUser and GetConnectionUnixProcessID with argument "org.freedesktop.DBus" will now return details of the dbus-daemon itself. This is required to be able to call SetEnvironment on systemd. (fd.o #92857, Jan Alexander Steffens) Fixes: • Make UpdateActivationEnvironment always fail with AccessDenied on the system bus. Previously, it was possible to configure it so root could call it, but the environment variables were not actually used, because the launch helper would discard them. (fd.o #92857, Jan Alexander Steffens) • On Unix with --systemd-activation on a user bus, make UpdateActivationEnvironment pass on its arguments to systemd's SetEnvironment method, solving inconsistency between the environments used for traditional activation and systemd user-service activation. (fd.o #92857, Jan Alexander Steffens) • On Windows, don't crash if or --syslog is used (fd.o #92538, Ralf Habacker) • On Windows, fix a memory leak when setting a DBusError from a Windows error (fd.o #92721, Ralf Habacker) • On Windows, don't go into infinite recursion if we abort the process with backtraces enabled (fd.o #92721, Ralf Habacker) • Fix various failing tests, variously on Windows and cross-platform: · don't test system.conf features (users, groups) that only make sense on the system bus, which is not supported on Windows · don't call _dbus_warn() when we skip a test, since it is fatal · fix computation of expected · when running TAP tests, translate newlines to Unix format, fixing cross-compiled tests under Wine on Linux · don't stress-test refcounting under Wine, where it's really slow · stop assuming that a message looped-back to the test will be received immediately · skip some system bus tests on Windows since they make no sense there (fd.o #92538, fd.o #92721; Ralf Habacker, Simon McVittie) D-Bus 1.10.2 (2015-10-26) == The “worst pies in London” release. Fixes: • Correct error handling for activation: if there are multiple attempts to activate the same service and it fails immediately, the first attempt would get the correct reply, but the rest would time out. We now send the same error reply to each attempt. (fd.o #92200, Simon McVittie) • If BecomeMonitor is called with a syntactically invalid match rule, don't crash with an assertion failure, fixing a regression in 1.9.10. This was not exploitable as a denial of service, because the check for a privileged user is done first. (fd.o #92298, Simon McVittie) • On Linux with --enable-user-session, add the bus address to the environment of systemd services for better backwards compatibility (fd.o #92612, Jan Alexander Steffens) • On Windows, fix the logic for replacing the installation prefix in service files' Exec lines (fd.o #83539; Milan Crha, Simon McVittie) • On Windows, if installed in the conventional layout with ${prefix}/etc and ${prefix}/share, use relative paths between bus configuration files to allow the tree to be relocated (fd.o #92028, Simon McVittie) • Make more of the regression tests pass in Windows builds (fd.o #92538, Simon McVittie) D-Bus 1.10.0 (2015-08-25) == The “0x20” release. This is a new stable branch, recommended for use in OS distributions. Fixes since 1.9.20: • distribute test/tap-test.sh.in, even if the tarball was built without tests enabled (fd.o #91684, Simon McVittie) • work around a fd leak in libcap-ng < 0.7.7 (fd.o #91684, Simon McVittie) Summary of major changes since 1.8.0: • The basic setup for the well-known system and session buses is now done in read-only files in ${datadir} (normally /usr/share). See the NEWS entry for 1.9.18 for details. • AppArmor integration has been merged, with features similar to the pre-existing SELinux integration. It is mostly compatible with the patches previously shipped by Ubuntu, with one significant change: Ubuntu's GetConnectionAppArmorSecurityContext method has been superseded by GetConnectionCredentials and was not included. • The --enable-user-session configure option can be enabled by OS integrators intending to use systemd to provide a session bus per user (in effect, treating all concurrent graphical and non-graphical login sessions as one large session). • The new listenable address mode "unix:runtime=yes" listens on $XDG_RUNTIME_DIR/bus, the same AF_UNIX socket used by the systemd user session. libdbus and "dbus-launch --autolaunch" will connect to this address by default. GLib ≥ 2.45.3 and sd-bus ≥ 209 have a matching default. • All executables are now dynamically linked to libdbus-1. Previously, some executables, most notably dbus-daemon, were statically linked to a specially-compiled variant of libdbus. This results in various private functions in the _dbus namespace being exposed by the shared library. These are not API, and must not be used outside the dbus source tree. • On platforms with ELF symbol versioning, all public symbols are versioned LIBDBUS_1_3. New bus APIs: • org.freedesktop.DBus.GetConnectionCredentials returns LinuxSecurityLabel where supported • org.freedesktop.DBus.Monitoring interface (privileged) · BecomeMonitor method supersedes match rules with eavesdrop=true, which are now deprecated • org.freedesktop.DBus.Stats interface (semi-privileged) · now enabled by default · new GetAllMatchRules method • org.freedesktop.DBus.Verbose interface (not normally compiled) · toggles the effect of DBUS_VERBOSE New executables: • dbus-test-tool • dbus-update-activation-environment New optional dependencies: • The systemd: pseudo-transport requires libsystemd or libsd-daemon • Complete documentation requires Ducktype and yelp-tools • Full test coverage requires GLib 2.36 and PyGI • AppArmor integration requires libapparmor and optionally libaudit Dependencies removed: • dbus-glib D-Bus 1.9.20 (2015-08-06) == The “Remember Tomorrow” release. This is a release-candidate for D-Bus 1.10.0. OS distribution vendors should test it. Fixes: • Don't second-guess what the ABI of poll() is, allowing it to be used on Integrity RTOS and other unusual platforms (fd.o #90314; Rolland Dudemaine, Simon McVittie) • Don't duplicate audit subsystem integration if AppArmor and SELinux are both enabled (fd.o #89225, Simon McVittie) • Log audit events for AppArmor/SELinux policy violations whenever we have CAP_AUDIT_WRITE, even if not the system bus (fd.o #83856, Laurent Bigonville) D-Bus 1.9.18 (2015-07-21) == The “Pirate Elite” release. Configuration changes: • The basic setup for the well-known system and session buses is now done in read-only files in ${datadir}, moving a step closer to systems that can operate with an empty /etc directory. In increasing order of precedence: · ${datadir}/dbus-1/s*.conf now perform the basic setup such as setting the default message policies. · ${sysconfdir}/dbus-1/s*.conf are now optional. By default dbus still installs a trivial version of each, for documentation purposes; putting configuration directives in these files is deprecated. · ${datadir}/dbus-1/s*.d/ are now available for third-party software to install "drop-in" configuration snippets (any packages using those directories should explicitly depend on at least this version of dbus). · ${sysconfdir}/dbus-1/s*.d/ are also still available for sysadmins or third-party software to install "drop-in" configuration snippets · ${sysconfdir}/dbus-1/s*-local.conf are still available for sysadmins' overrides ${datadir} is normally /usr/share, ${sysconfdir} is normally /etc, and "s*" refers to either system or session as appropriate. (fd.o #89280, Dimitri John Ledkov) Fixes: • Fix a memory leak when GetConnectionCredentials() succeeds (fd.o #91008, Jacek Bukarewicz) • Ensure that dbus-monitor does not reply to messages intended for others, resulting in its own disconnection (fd.o #90952, Simon McVittie) D-Bus 1.9.16 (2015-05-14) == The “titanium barns” release. Dependencies: • Automake 1.13 is now required when compiling from git or modifying the build system. Security hardening: • On Unix platforms, change the default configuration for the session bus to only allow EXTERNAL authentication (secure kernel-mediated credentials-passing), as was already done for the system bus. This avoids falling back to DBUS_COOKIE_SHA1, which relies on strongly unpredictable pseudo-random numbers. If you are using D-Bus over the (unencrypted!) tcp: or nonce-tcp: transport, in conjunction with DBUS_COOKIE_SHA1 and a shared home directory using NFS or similar, you will need to reconfigure the session bus to accept DBUS_COOKIE_SHA1 by commenting out the element. This configuration is not recommended. (fd.o #90414, Simon McVittie) • When asked for random numbers for DBUS_COOKIE_SHA1, the nonce-tcp: transport, UUIDs or any other reason, fail if we cannot obtain entropy (from /dev/urandom or CryptGenRandom()) or an out-of-memory condition occurs, instead of silently falling back to low-entropy pseudorandom numbers from rand(). (fd.o #90414; Simon McVittie, Ralf Habacker) Enhancements: • Add dbus_message_iter_get_element_count() (fd.o #30350; Christian Dywan, Simon McVittie) • Introduce new internal DBusSocket and DBusPollable types so we can stop treating the Windows SOCKET type as if it was int. DBusSocket is specifically a socket, cross-platform. DBusPollable is whatever _dbus_poll() can act on, i.e. a fd on Unix or a SOCKET on Windows. (fd.o #89444; Ralf Habacker, Simon McVittie) • All regression tests now output TAP (fd.o #89846, Simon McVittie) • Internal APIs consistently use signed values for timestamps (fd.o #18494, Peter McCurdy) • Improve diagnostics when UpdateActivationEnvironment calls are rejected (fd.o #88812, Simon McVittie) • Clean up a lot of compiler warnings (fd.o #17289, fd.o #89284; Ralf Habacker, Simon McVittie) Fixes: • Add locking to DBusCounter's reference count and notify function (fd.o #89297, Adrian Szyndela) • Ensure that DBusTransport's reference count is protected by the corresponding DBusConnection's lock (fd.o #90312, Adrian Szyndela) • Correctly release DBusServer mutex before early-return if we run out of memory while copying authentication mechanisms (fd.o #90021, Ralf Habacker) • Make dbus-test-tool and dbus-update-activation-environment portable to Windows (fd.o #90089, Ralf Habacker) • Correctly initialize all fields of DBusTypeReader (fd.o #90021; Ralf Habacker, Simon McVittie) • Fix some missing \n in verbose (debug log) messages (fd.o #90004, Ralf Habacker) • Clean up some memory and fd leaks in test code and tools (fd.o #90021, Ralf Habacker) • Fix a NULL dereference if the dbus-daemon cannot read a configuration directory for a reason that is not ENOENT (fd.o #90021, Ralf Habacker) • CMake generates a versioned shared library even if the revision is 0, as it usually is on the development branch. (fd.o #89450, Ralf Habacker) D-Bus 1.9.14 (2015-03-02) == The “don't stand in the poison cloud” release. Dependencies: • dbus-daemon and dbus-daemon-launch-helper now require libdbus. They were previously linked to a static version of libdbus. • The tests no longer require dbus-glib in order to exercise the libdbus shared library; they are always linked to libdbus now. Build-time configuration: • The new --enable-user-session option, off by default, can be enabled by OS integrators intending to use systemd to provide a session bus per user (in effect, treating all concurrent graphical and non-graphical login sessions as one large session) Enhancements: • All executables are now linked dynamically to libdbus. (fd.o #83115; Bertrand SIMONNET, Simon McVittie, Ralf Habacker) • On platforms that support them (GNU libc and possibly others), libdbus now has versioned symbols for its public API. All public symbols (visible in the header files) are currently versioned as LIBDBUS_1_3; private symbols starting with _dbus or dbus_internal have a version that changes with each release, and must not be used by applications. (also fd.o #83115) • New listenable address mode "unix:runtime=yes" which listens on a real filesystem (non-abstract) socket $XDG_RUNTIME_DIR/bus (fd.o #61303; Colin Walters, Alexander Larsson, Simon McVittie) • Add optional systemd units for a per-user bus listening on $XDG_RUNTIME_DIR/bus (fd.o #61301; Simon McVittie, Colin Walters) • On Unix platforms, both libdbus and "dbus-launch --autolaunch" default to connecting to $XDG_RUNTIME_DIR/bus if it is a socket (also fd.o #61301) • New dbus-update-activation-environment tool uploads environment variables to "dbus-daemon --session" and optionally "systemd --user", primarily as a way to keep the per-user bus compatible with distributions' existing X11 login scripts (also fd.o #61301) • elements in dbus-daemon configuration are now silently ignored if the directory does not exist. (fd.o #89280, Dimitri John Ledkov) • Add microsecond-resolution timestamps to the default output of dbus-monitor and dbus-send (fd.o #88896; Ralf Habacker, Simon McVittie) Fixes: • Fix a race condition in the 'monitor' test introduced in 1.9.10 (fd.o #89222, Simon McVittie) D-Bus 1.9.12 (2015-02-19) == The “monster lasagna” release. Dependencies: • Ducktype and yelp-tools are now required to build complete documentation (they are optional for normal builds). Enhancements: • D-Bus Specification version 0.26 · GetConnectionCredentials can return LinuxSecurityLabel or WindowsSID · document the BecomeMonitor method • On Linux, add LinuxSecurityLabel to GetConnectionCredentials (fd.o #89041; Tyler Hicks, Simon McVittie) • On Linux, add support for AppArmor mediation of message sending and receiving and name ownership (paralleling existing SELinux mediation support), and eavesdropping (a new check, currently AppArmor-specific) (fd.o #75113; John Johansen, Tyler Hicks, Simon McVittie) • In dbus-send and dbus-monitor, pretty-print \0-terminated bytestrings that have printable ASCII contents; we previously only did this for unterminated bytestrings (fd.o #89109, Simon McVittie) • Add a guide to designing good D-Bus APIs (fd.o #88994, Philip Withnall) • On Windows, add WindowsSID to GetConnectionCredentials (fd.o #54445, Ralf Habacker) • Improve clarity of dbus-monitor --profile output and add more columns (fd.o #89165, Ralf Habacker) • Add a man page for dbus-test-tool, and build it under CMake as well as Autotools (fd.o#89086, Simon McVittie) • If dbus-daemon was compiled with --enable-verbose, add a D-Bus API to control it at runtime, overriding the DBUS_VERBOSE environment variable (fd.o #88896, Ralf Habacker) Fixes: • Reduce the number of file descriptors used in the fd-passing test, avoiding failure under the default Linux fd limit, and automatically skip it if the rlimit is too small (fd.o #88998, Simon McVittie) D-Bus 1.9.10 (2015-02-09) == The “sad cyborgs” release. Security fixes merged from 1.8.16: • Do not allow non-uid-0 processes to send forged ActivationFailure messages. On Linux systems with systemd activation, this would allow a local denial of service: unprivileged processes could flood the bus with these forged messages, winning the race with the actual service activation and causing an error reply to be sent back when service auto-activation was requested. This does not prevent the real service from being started, so the attack only works while the real service is not running. (CVE-2015-0245, fd.o #88811; Simon McVittie) Enhancements: • The new Monitoring interface in the dbus-daemon lets dbus-monitor and similar tools receive messages without altering the security properties of the system bus, by calling the new BecomeMonitor method on a private connection. This bypasses the normal and rules entirely, so to preserve normal message-privacy assumptions, only root is allowed to do this on the system bus. Restricted environments, such as Linux with LSMs, should lock down access to the Monitoring interface. (fd.o #46787, Simon McVittie) • dbus-monitor uses BecomeMonitor to capture more traffic, if the dbus-daemon supports it and access permissions allow it. It still supports the previous approach ("eavesdropping" match rules) for compatibility with older bus daemons. (fd.o #46787, Simon) • dbus-monitor can now log the message stream as binary data for later analysis, with either no extra framing beyond the normal D-Bus headers, or libpcap-compatible framing treating each D-Bus message as a captured packet. (fd.o #46787, Simon) Other fixes: • Fix some CMake build regressions (fd.o #88964, Ralf Habacker) • On Unix, forcibly terminate regression tests after 60 seconds to prevent them from blocking continuous integration frameworks (fd.o #46787, Simon) D-Bus 1.9.8 (2015-02-03) == The “all the types of precipitation” release. Dependencies: • full test coverage now requires GLib 2.36 • full test coverage now requires PyGI (PyGObject 3, "import gi.repository.GObject") instead of the obsolete PyGObject 2 ("import gobject") Enhancements: • add GLib-style "installed tests" (fd.o #88810, Simon McVittie) • better regression test coverage, including systemd activation (fd.o #57952, #88810; Simon McVittie) Fixes: • fatal errors correctly make the dbus-daemon exit even if is turned off (fd.o #88808, Simon McVittie) • TCP sockets on Windows no longer fail to listen approximately 1 time in 256, caused by a logic error that should have always made it fail but was mitigated by incorrect endianness for the port number (fd.o #87999, Ralf Habacker) • fix some Windows build failures (fd.o #88009, #88010; Ralf Habacker) • on Windows, allow up to 8K connections to the dbus-daemon instead of the previous 64, completing a previous fix which only worked under Autotools (fd.o #71297, Ralf Habacker) • on Windows, if the IP family is unspecified only use IPv4, to mitigate IPv6 not working correctly (fd.o #87999, Ralf Habacker) • fix some unlikely memory leaks on OOM (fd.o #88087, Simon McVittie) • lcov code coverage analysis works again (fd.o #88808, Simon McVittie) • fix an unused function error with --disable-embedded-tests (fd.o #87837, Thiago Macieira) D-Bus 1.9.6 (2015-01-05) == The “I do have a bread knife” release. Security hardening: • Do not allow calls to UpdateActivationEnvironment from uids other than the uid of the dbus-daemon. If a system service installs unsafe security policy rules that allow arbitrary method calls (such as CVE-2014-8148) then this prevents memory consumption and possible privilege escalation via UpdateActivationEnvironment. We believe that in practice, privilege escalation here is avoided by dbus-daemon-launch-helper sanitizing its environment; but it seems better to be safe. • Do not allow calls to UpdateActivationEnvironment or the Stats interface on object paths other than /org/freedesktop/DBus. Some system services install unsafe security policy rules that allow arbitrary method calls to any destination, method and interface with a specified object path; while less bad than allowing arbitrary method calls, these security policies are still harmful, since dbus-daemon normally offers the same API on all object paths and other system services might behave similarly. Other fixes: • Add missing initialization so GetExtendedTcpTable doesn't crash on Windows Vista SP0 (fd.o #77008, Илья А. Ткаченко) D-Bus 1.9.4 (2014-11-24) == The “extra-sturdy caramel” release. Fixes: • Partially revert the CVE-2014-3639 patch by increasing the default authentication timeout on the system bus from 5 seconds back to 30 seconds, since this has been reported to cause boot regressions for some users, mostly with parallel boot (systemd) on slower hardware. On fast systems where local users are considered particularly hostile, administrators can return to the 5 second timeout (or any other value in milliseconds) by saving this as /etc/dbus-1/system-local.conf: 5000 (fd.o #86431, Simon McVittie) • Add a message in syslog/the Journal when the auth_timeout is exceeded (fd.o #86431, Simon McVittie) • Send back an AccessDenied error if the addressed recipient is not allowed to receive a message (and in builds with assertions enabled, don't assert under the same conditions). (fd.o #86194, Jacek Bukarewicz) D-Bus 1.9.2 (2014-11-10) == The “structurally unsound flapjack” release. Security fixes: • Increase dbus-daemon's RLIMIT_NOFILE rlimit to 65536 so that CVE-2014-3636 part A cannot exhaust the system bus' file descriptors, completing the incomplete fix in 1.8.8. (CVE-2014-7824, fd.o #85105; Simon McVittie, Alban Crequy) Enhancements: • D-Bus Specification version 0.25 · new value 'const' for EmitsChangedSignal annotation (fd.o #72958, Lennart Poettering) · new ALLOW_INTERACTIVE_AUTHORIZATION flag, for PolicyKit and similar (fd.o #83449; Lennart Poettering, Simon McVittie) · annotate table of types with reserved/basic/container, and for basic types, fixed/string-like · clarify arbitrary limits by quoting them in mebibytes • New API: add accessors for the ALLOW_INTERACTIVE_AUTHORIZATION flag (fd.o #83449, Simon McVittie) • Add dbus-test-tool, a D-Bus swiss army knife with multiple subcommands, useful for debugging and performance testing: · dbus-test-tool spam: send repeated messages · dbus-test-tool echo: send an empty reply for all method calls · dbus-test-tool black-hole: do not reply to method calls (fd.o #34140; Alban Crequy, Simon McVittie, Will Thompson) • Add support for process ID in credentials-passing on NetBSD (fd.o #69702, Patrick Welche) • Add an example script to find potentially undesired match rules (fd.o #84598, Alban Crequy) • Document the central assumption that makes our use of credentials-passing secure (fd.o #83499, Simon McVittie) • Replace the dbus-glib section of the tutorial with a GDBus recommendation, and add some links to GDBus and QtDBus documentation (fd.o #25140, Simon McVittie) Fixes: • Use a less confusing NoReply message when disconnected with a reply pending (fd.o #76112, Simon McVittie) • Make the .pc file relocatable by letting pkg-config do all variable expansion itself (fd.o #75858, Руслан Ижбулатов) • Fix a build failure on platforms with kqueue, which regressed in 1.9.0 (fd.o #85563, Patrick Welche) • Consistently save errno after socket calls (fd.o #83625, Simon McVittie) • In dbus-spawn, when the grandchild process exits due to a failed exec(), do not lose the exec() errno (fd.o #24821, Simon McVittie) • Do not fail the tests if a parent process has leaked non-close-on-exec file descriptors to us (fd.o #73689, fd.o #83899; Simon McVittie) • Do not fail the tests on Unix platforms with incomplete credentials-passing support, but do fail if we can't pass credentials on a platform where it is known to work: Linux, FreeBSD, OpenBSD, NetBSD (fd.o #69702, Simon McVittie) • Detect accept4, dirfd, inotify_init1, pipe2, and Unix fd passing when building with cmake, and expand test coverage there (fd.o #73689; Ralf Habacker, Simon McVittie) D-Bus 1.9.0 (2014-10-01) == The “tiered cheeses” release. Requirements: • Support for the systemd: (LISTEN_FDS) pseudo-transport on Linux now requires either the libsystemd or libsd-daemon shared library, dropping the embedded convenience copy of sd-daemon (fd.o #71818, Simon) Build-time configuration changes: • The Stats interface is now enabled by default, and locked-down to root-only on the system bus. Configure with --disable-stats to disable it altogether on memory- or disk-constrained systems, or see ${docdir}/examples/ to open it up to non-root users on the system bus or restrict access on the session bus. (fd.o #80759; Simon McVittie, Alban Crequy) • The CMake build system now builds the same shared library name as Autotools on at least Linux and Windows: - on Linux (and perhaps other Unix platforms), it previously built libdbus-1.so, but now builds libdbus-1.so.3.* with development symlink libdbus-1.so and SONAME/symlink libdbus-1.so.3 - on Windows, it previously built either libdbus-1.dll (release) or libdbus-1d.dll (debug), but now builds libdbus-1-3.dll, copied to libdbus-1.dll for compatibility with older applications. (fd.o #74117, Ralf Habacker) Enhancements: • D-Bus Specification version 0.24 · document how to quote match rules (fd.o #24307, Simon McVittie) · explicitly say that most message types never expect a reply regardles of whether they have NO_REPLY_EXPECTED (fd.o #75749, Simon McVittie) • on Unix platforms, disable Nagle's algorithm on TCP connections to improve initial latency (fd.o #75544, Matt Hoosier) • use backtrace() if it is in -lexecinfo instead of libc, as on NetBSD (fd.o #69702, Patrick Welche) • in dbus-monitor, print more information about file descriptors (fd.o #80603, Alban Crequy) • do not install system bus configuration if built for Windows (fd.o #83583; Ralf Habacker, Simon McVittie) • Add GetAllMatchRules to the Stats interface (fd.o #24307, Alban Crequy) • Add a regression test for file descriptor passing (fd.o #83622, Simon McVittie) Fixes: • fix an incorrect error message if a Unix socket path is too long (fd.o #73887, Antoine Jacoutot) • in an MSYS/Cygwin environment, pass Unix-style filenames to xmlto, fixing documentation generation (fd.o #75860, Руслан Ижбулатов) • in Unix with X11, avoid giving dbus-launch a misleading argv[0] in ps(1) (fd.o #69716, Chengwei Yang) • avoid calling poll() with timeout < -1, which is considered invalid on FreeBSD and NetBSD (fd.o #78480, Jaap Boender) • be portable to BSD-derived platforms where O_CLOEXEC is unavailable in libc (like Mac OS X 10.6), or available in libc but unsupported by the kernel (fd.o #77032; rmvsxop, OBATA Akio, Patrick Welche) • Fix include path for test/internal/*.c with cmake (Ralf Habacker) • Documentation improvements (fd.o #80795, #84313; Thomas Haller, Sebastian Rasmussen) • in dbus-monitor, do not leak file descriptors that we have monitored (fd.o #80603, Alban Crequy) • Set the close-on-exec flag for the inotify file descriptor, even if built with CMake or older libc (fd.o #73689, Simon McVittie) • Remove some LGPL code from the Windows dbus-daemon (fd.o #57272, Ralf Habacker) D-Bus 1.8.8 (2014-09-16) == The "smashy smashy egg man" release. Security fixes: • Do not accept an extra fd in the padding of a cmsg message, which could lead to a 4-byte heap buffer overrun. (CVE-2014-3635, fd.o #83622; Simon McVittie) • Reduce default for maximum Unix file descriptors passed per message from 1024 to 16, preventing a uid with the default maximum number of connections from exhausting the system bus' file descriptors under Linux's default rlimit. Distributors or system administrators with a more restrictive fd limit may wish to reduce these limits further. Additionally, on Linux this prevents a second denial of service in which the dbus-daemon can be made to exceed the maximum number of fds per sendmsg() and disconnect the process that would have received them. (CVE-2014-3636, fd.o #82820; Alban Crequy) • Disconnect connections that still have a fd pending unmarshalling after a new configurable limit, pending_fd_timeout (defaulting to 150 seconds), removing the possibility of creating an abusive connection that cannot be disconnected by setting up a circular reference to a connection's file descriptor. (CVE-2014-3637, fd.o #80559; Alban Crequy) • Reduce default for maximum pending replies per connection from 8192 to 128, mitigating an algorithmic complexity denial-of-service attack (CVE-2014-3638, fd.o #81053; Alban Crequy) • Reduce default for authentication timeout on the system bus from 30 seconds to 5 seconds, avoiding denial of service by using up all unauthenticated connection slots; and when all unauthenticated connection slots are used up, make new connection attempts block instead of disconnecting them. (CVE-2014-3639, fd.o #80919; Alban Crequy) Other fixes: • Check for libsystemd from systemd >= 209, falling back to the older separate libraries if not found (Umut Tezduyar Lindskog, Simon McVittie) • On Linux, use prctl() to disable core dumps from a test executable that deliberately raises SIGSEGV to test dbus-daemon's handling of that condition (fd.o #83772, Simon McVittie) • Fix compilation with --enable-stats (fd.o #81043, Gentoo #507232; Alban Crequy) • Improve documentation for running tests on Windows (fd.o #41252, Ralf Habacker) D-Bus 1.8.6 (2014-06-02) == Security fixes: • On Linux ≥ 2.6.37-rc4, if sendmsg() fails with ETOOMANYREFS, silently drop the message. This prevents an attack in which a malicious client can make dbus-daemon disconnect a system service, which is a local denial of service. (fd.o #80163, CVE-2014-3532; Alban Crequy) • Track remaining Unix file descriptors correctly when more than one message in quick succession contains fds. This prevents another attack in which a malicious client can make dbus-daemon disconnect a system service. (fd.o #79694, fd.o #80469, CVE-2014-3533; Alejandro Martínez Suárez, Simon McVittie, Alban Crequy) Other fixes: • When dbus-launch --exit-with-session starts a dbus-daemon but then cannot attach to a session, kill the dbus-daemon as intended (fd.o #74698, Роман Донченко) D-Bus 1.8.4 (2014-06-10) == Security fix: • Alban Crequy at Collabora Ltd. discovered and fixed a denial-of-service flaw in dbus-daemon, part of the reference implementation of D-Bus. Additionally, in highly unusual environments the same flaw could lead to a side channel between processes that should not be able to communicate. (CVE-2014-3477, fd.o #78979) D-Bus 1.8.2 (2014-04-30) == The “nobody wants red” release. Enhancements: • in the CMake build system, add some hints for Linux users cross-compiling Windows D-Bus binaries to be able to run tests under Wine (fd.o #41252, Ralf Habacker) • add Documentation key to dbus.service (fd.o #77447, Cameron Norman) Fixes: • in "dbus-uuidgen --ensure", try to copy systemd's /etc/machine-id to /var/lib/dbus/machine-id instead of generating an entirely new ID (fd.o #77941, Simon McVittie) • if dbus-launch receives an X error very quickly, do not kill unrelated processes (fd.o #74698, Роман Донченко) • on Windows, allow up to 8K connections to the dbus-daemon, instead of the previous 64 (fd.o #71297; Cristian Onet, Ralf Habacker) • cope with \r\n newlines in regression tests, since on Windows, dbus-daemon.exe uses text mode (fd.o #75863, Руслан Ижбулатов) D-Bus 1.8.0 (2014-01-20) == The “Wolverine distrusts my printer” release. This starts a new stable branch. The 1.6.x branch is now considered to be outdated, and will only receive fixes for serious bugs such as security flaws. The 1.4.x and 1.2.x branches no longer have upstream support and are unlikely to get any more releases, but if distributors still need to support them, please share security patches via upstream. Summary of changes since 1.6.x: • libdbus always behaves as if dbus_threads_init_default() had been called (thread-safety by default) • new dbus-run-session tool, replacing certain misuses of dbus-launch • dbus-monitor can talk to outdated versions of dbus-daemon again • new org.freedesktop.DBus.GetConnectionCredentials method • GetConnectionUnixProcessID also works correctly on Windows, returning the Windows process ID • GetConnectionWindowsSID returns the correct SID on Windows • expat is required, libxml2 can no longer be used as a substitute • the userDB cache is required, and cannot be disabled • a 64-bit integer type (either int, long, long long or _int64) is required • better systemd-journald integration on Linux • fixed long-standing fd and array leaks when failing to parse a message • fixed referenced-but-never-freed parent nodes (effectively memory leaks) when using certain object-path allocation patterns, notably in Avahi • better defaults for Windows support • better CMake support • better portability to mingw32, FreeBSD, NetBSD, QNX and Hurd • the source language for the man pages is now Docbook XML Enhancements since 1.7.10: • Enhance the CMake build system to check for GLib and compile/run a subset of the regression tests (fd.o #41252, #73495; Ralf Habacker) Fixes since 1.7.10: • don't rely on va_copy(), use DBUS_VA_COPY() wrapper (fd.o #72840, Ralf Habacker) • fix compilation of systemd journal support on older systemd versions where sd-journal.h doesn't include syslog.h (fd.o #73455, Ralf Habacker) • fix compilation on older MSVC versions by including stdlib.h (fd.o #73455, Ralf Habacker) • Allow to appear in an included configuration file (fd.o #73475, Matt Hoosier) Test behaviour changes since 1.7.10: • If the tests crash with an assertion failure, they no longer default to blocking for a debugger to be attached. Set DBUS_BLOCK_ON_ABORT in the environment if you want the old behaviour. • To improve debuggability, the dbus-daemon and dbus-daemon-eavesdrop tests can be run with an external dbus-daemon by setting DBUS_TEST_DAEMON_ADDRESS in the environment. Test-cases that require an unusually-configured dbus-daemon are skipped. D-Bus 1.7.10 (2014-01-06) == The “weighted companion cube” release. This is a release candidate for D-Bus 1.8. D-Bus Specification 0.23: • don't require messages with no INTERFACE to be dispatched (fd.o #68597, Simon McVittie) • document "tcp:bind=..." and "nonce-tcp:bind=..." (fd.o #72301, Chengwei Yang) • define "listenable" and "connectable" addresses, and discuss the difference (fd.o #61303, Simon McVittie) Enhancements: • support printing Unix file descriptors in dbus-send, dbus-monitor (fd.o #70592, Robert Ancell) • don't install systemd units if --disable-systemd is given (fd.o #71818, Chengwei Yang) Fixes: • don't leak memory on out-of-memory while listing activatable or active services (fd.o #71526, Radoslaw Pajak) • fix undefined behaviour in a regression test (fd.o #69924, DreamNik) • escape Unix socket addresses correctly (fd.o #46013, Chengwei Yang) • on SELinux systems, don't assume that SECCLASS_DBUS, DBUS__ACQUIRE_SVC and DBUS__SEND_MSG are numerically equal to their values in the reference policy (fd.o #88719, osmond sun) • define PROCESS_QUERY_LIMITED_INFORMATION if missing from MinGW < 4 headers (fd.o #71366, Matt Fischer) • define WIN32_LEAN_AND_MEAN to avoid conflicts between winsock.h and winsock2.h (fd.o #71405, Matt Fischer) • do not return failure from _dbus_read_nonce() with no error set, preventing a potential crash (fd.o #72298, Chengwei Yang) • on BSD systems, avoid some O(1)-per-process memory and fd leaks in kqueue, preventing test failures (fd.o #69332, fd.o #72213; Chengwei Yang) • fix warning spam on Hurd by not trying to set SO_REUSEADDR on Unix sockets, which doesn't do anything anyway on at least Linux and FreeBSD (fd.o #69492, Simon McVittie) • fix use of TCP sockets on FreeBSD and Hurd by tolerating EINVAL from sendmsg() with SCM_CREDS (retrying with plain send()), and looking for credentials more correctly (fd.o #69492, Simon McVittie) • ensure that tests run with a temporary XDG_RUNTIME_DIR to avoid getting mixed up in XDG/systemd "user sessions" (fd.o #61301, Simon McVittie) • refresh cached policy rules for existing connections when bus configuration changes (fd.o #39463, Chengwei Yang) D-Bus 1.7.8 (2013-11-01) == The “extreme hills” release. Dependencies: • If systemd support is enabled, libsystemd-journal is now required. Enhancements: • When activating a non-systemd service under systemd, annotate its stdout/stderr with its bus name in the Journal. Known limitation: because the socket is opened before forking, the process will still be logged as if it had dbus-daemon's process ID and user ID. (fd.o #68559, Chengwei Yang) • Document more configuration elements in dbus-daemon(1) (fd.o #69125, Chengwei Yang) Fixes: • Don't leak string arrays or fds if dbus_message_iter_get_args_valist() unpacks them and then encounters an error (fd.o #21259, Chengwei Yang) • If compiled with libaudit, retain CAP_AUDIT_WRITE so we can write disallowed method calls to the audit log, fixing a regression in 1.7.6 (fd.o #49062, Colin Walters) • path_namespace='/' in match rules incorrectly matched nothing; it now matches everything. (fd.o #70799, Simon McVittie) D-Bus 1.7.6 (2013-10-09) == The “CSI Shrewsbury” release. Build-time configuration changes: • Directory change notification via dnotify on Linux is no longer supported; it hadn't compiled successfully since 2010 in any case. If you don't have inotify (Linux) or kqueue (*BSD), you will need to send SIGHUP to the dbus-daemon when its configuration changes. (fd.o #33001, Chengwei Yang) • Compiling with --disable-userdb-cache is no longer supported; it didn't work since at least 2008, and would lead to an extremely slow dbus-daemon even it worked. (fd.o #15589, #17133, #66947; Chengwei Yang) • The DBUS_DISABLE_ASSERTS CMake option didn't actually disable most assertions. It has been renamed to DBUS_DISABLE_ASSERT to be consistent with the Autotools build system. (fd.o #66142, Chengwei Yang) • --with-valgrind=auto enables Valgrind instrumentation if and only if valgrind headers are available. The default is still --with-valgrind=no. (fd.o #56925, Simon McVittie) Dependencies: • Platforms with no 64-bit integer type are no longer supported. (fd.o #65429, Simon McVittie) • GNU make is now (documented to be) required. (fd.o #48277, Simon McVittie) • Full test coverage no longer requires dbus-glib, although the tests do not exercise the shared library (only a static copy) if dbus-glib is missing. (fd.o #68852, Simon McVittie) Enhancements: • D-Bus Specification 0.22 · Document GetAdtAuditSessionData() and GetConnectionSELinuxSecurityContext() (fd.o #54445, Simon) · Fix example .service file (fd.o #66481, Chengwei Yang) · Don't claim D-Bus is "low-latency" (lower than what?), just give factual statements about it supporting async use (fd.o #65141, Justin Lee) · Document the contents of .service files, and the fact that system services' filenames are constrained (fd.o #66608; Simon McVittie, Chengwei Yang) • Be thread-safe by default on all platforms, even if dbus_threads_init_default() has not been called. For compatibility with older libdbus, library users should continue to call dbus_threads_init_default(): it is harmless to do so. (fd.o #54972, Simon McVittie) • Add GetConnectionCredentials() method (fd.o #54445, Simon) • New API: dbus_setenv(), a simple wrapper around setenv(). Note that this is not thread-safe. (fd.o #39196, Simon) • Add dbus-send --peer=ADDRESS (connect to a given peer-to-peer connection, like --address=ADDRESS in previous versions) and dbus-send --bus=ADDRESS (connect to a given bus, like dbus-monitor --address=ADDRESS). dbus-send --address still exists for backwards compatibility, but is no longer documented. (fd.o #48816, Andrey Mazo) • Windows-specific: · "dbus-daemon --nofork" is allowed on Windows again. (fd.o #68852, Simon McVittie) Fixes: • Avoid an infinite busy-loop if a signal interrupts waitpid() (fd.o #68945, Simon McVittie) • Clean up memory for parent nodes when objects are unexported (fd.o #60176, Thomas Fitzsimmons) • Make dbus_connection_set_route_peer_messages(x, FALSE) behave as documented. Previously, it assumed its second parameter was TRUE. (fd.o #69165, Chengwei Yang) • Escape addresses containing non-ASCII characters correctly (fd.o #53499, Chengwei Yang) • Document search order correctly (fd.o #66994, Chengwei Yang) • Don't crash on "dbus-send --session / x.y.z" which regressed in 1.7.4. (fd.o #65923, Chengwei Yang) • If malloc() returns NULL in _dbus_string_init() or similar, don't free an invalid pointer if the string is later freed (fd.o #65959, Chengwei Yang) • If malloc() returns NULL in dbus_set_error(), don't va_end() a va_list that was never va_start()ed (fd.o #66300, Chengwei Yang) • fix build failure with --enable-stats (fd.o #66004, Chengwei Yang) • fix a regression test on platforms with strict alignment (fd.o #67279, Colin Walters) • Avoid calling function parameters "interface" since certain Windows headers have a namespace-polluting macro of that name (fd.o #66493, Ivan Romanov) • Assorted Doxygen fixes (fd.o #65755, Chengwei Yang) • Various thread-safety improvements to static variables (fd.o #68610, Simon McVittie) • Make "make -j check" work (fd.o #68852, Simon McVittie) • Fix a NULL pointer dereference on an unlikely error path (fd.o #69327, Sviatoslav Chagaev) • Improve valgrind memory pool tracking (fd.o #69326, Sviatoslav Chagaev) • Don't over-allocate memory in dbus-monitor (fd.o #69329, Sviatoslav Chagaev) • dbus-monitor can monitor dbus-daemon < 1.5.6 again (fd.o #66107, Chengwei Yang) • Unix-specific: · If accept4() fails with EINVAL, as it can on older Linux kernels with newer glibc, try accept() instead of going into a busy-loop. (fd.o #69026, Chengwei Yang) · If socket() or socketpair() fails with EINVAL or EPROTOTYPE, for instance on Hurd or older Linux with a new glibc, try without SOCK_CLOEXEC. (fd.o #69073; Pino Toscano, Chengwei Yang) · Fix a file descriptor leak on an error code path. (fd.o #69182, Sviatoslav Chagaev) · dbus-run-session: clear some unwanted environment variables (fd.o #39196, Simon) · dbus-run-session: compile on FreeBSD (fd.o #66197, Chengwei Yang) · Don't fail the autolaunch test if there is no DISPLAY (fd.o #40352, Simon) · Use dbus-launch from the builddir for testing, not the installed copy (fd.o #37849, Chengwei Yang) · Fix compilation if writev() is unavailable (fd.o #69409, Vasiliy Balyasnyy) · Remove broken support for LOCAL_CREDS credentials passing, and document where each credential-passing scheme is used (fd.o #60340, Simon McVittie) · Make autogen.sh work on *BSD by not assuming GNU coreutils functionality (fd.o #35881, #69787; Chengwei Yang) · dbus-monitor: be portable to NetBSD (fd.o #69842, Chengwei Yang) · dbus-launch: stop using non-portable asprintf (fd.o #37849, Simon) · Improve error reporting from the setuid activation helper (fd.o #66728, Chengwei Yang) • Windows-specific: · Remove unavailable command-line options from 'dbus-daemon --help' (fd.o #42441, Ralf Habacker) · Add support for looking up local TCPv4 clients' credentials on Windows XP via the undocumented AllocateAndGetTcpExTableFromStack function (fd.o #66060, Ralf Habacker) · Fix insufficient dependency-tracking (fd.o #68505, Simon McVittie) · Don't include wspiapi.h, fixing a compiler warning (fd.o #68852, Simon McVittie) • Internal changes: · add DBUS_ENABLE_ASSERT, DBUS_ENABLE_CHECKS for less confusing conditionals (fd.o #66142, Chengwei Yang) · improve verbose-mode output (fd.o #63047, Colin Walters) · consolidate Autotools and CMake build (fd.o #64875, Ralf Habacker) · fix various unused variables, unusual build configurations etc. (fd.o #65712, #65990, #66005, #66257, #69165, #69410, #70218; Chengwei Yang, Vasiliy Balyasnyy) D-Bus 1.7.4 (2013-06-13) == The “but is your thread-safety thread-safe?” release. Security fixes: • CVE-2013-2168: Fix misuse of va_list that could be used as a denial of service for system services. Vulnerability reported by Alexandru Cornea. (Simon) Dependencies: • The Windows version of libdbus now contains a C++ source file, used to provide global initialization when the library is loaded. gcc (mingw*) users should ensure that g++ is also installed. • The libxml2-based configuration reader (which hasn't worked for 2.5 years, and was never the recommended option) has been removed. Expat is now a hard dependency. Enhancements: • It should now be safe to call dbus_threads_init_default() from any thread, at any time. Authors of loadable modules and plugins that use libdbus should consider doing so during initialization. (fd.o #54972, Simon McVittie) • Improve dbus-send documentation and command-line parsing (fd.o #65424, Chengwei Yang) Unix-specific: · dbus-run-session: experimental new tool to start a temporary D-Bus session, e.g. for regression tests or a text console, replacing certain uses of dbus-launch which weren't really correct (fd.o #39196, Simon) Other fixes: • In dbus-daemon, don't crash if a .service file starts with key=value (fd.o #60853, Chengwei Yang) • Unix-specific: · Fix a crash similar to CVE-2013-2168 the first time we try to use syslog on a platform not defining LOG_PERROR, such as Solaris or QNX. This regressed in 1.7.0. (Simon) · Fix an assertion failure if we try to activate systemd services before systemd connects to the bus (fd.o #50199, Chengwei Yang) · Avoid compiler warnings for ignoring the return from write() (Chengwei Yang) • Windows-specific: · Under cmake, install runtime libraries (DLLs) into bin/ instead of lib/ so that Windows finds them (fd.o #59733, Ralf Habacker) D-Bus 1.7.2 (2013-04-25) == The “only partially opaque” release. Configuration changes: • On non-QNX Unix platforms, the default limit on fds per message in the session bus configuration has reduced from 4096 to 1024. The default limit used on the system bus was already 1024. On QNX, both limits are reduced further, to 128. Enhancements: • D-Bus Specification 0.21 · Following Unicode Corrigendum #9, the noncharacters U+nFFFE, U+nFFFF, U+FDD0..U+FDEF are allowed in UTF-8 strings again. (fd.o #63072, Simon McVittie) Fixes: • Diagnose incorrect use of dbus_connection_get_data() with negative slot (i.e. before allocating the slot) rather than returning junk (fd.o #63127, Dan Williams) • Fix a cmake build regression since 1.7.0 (fd.o #63682; Ralf Habacker, Simon McVittie) • Unix-specific: · On Linux, link successfully with glibc 2.17 (fd.o #63166, Simon McVittie)   · Under systemd, log to syslog only, not stderr, avoiding duplication (fd.o #61399, #39987; Colin Walters, Dagobert Michelsen) · Under systemd, remove unnecessary dependency on syslog.socket (fd.o #63531, Cristian Rodríguez) · Include alloca.h for alloca() if available, fixing compilation on Solaris 10 (fd.o #63071, Dagobert Michelsen) · Allow use of systemd-logind without the rest of systemd (fd.o #62585, Martin Pitt) · When built with CMake, link to librt and use the right path for meinproc's XSLT stylesheets (fd.o #61637, Ralf Habacker) · Reduce the default limit on number of fds per message to 128 under QNX, working around an arbitrary OS limit (fd.o #61176, Matt Fischer) • Windows-specific: · Do not claim that all bus clients have the dbus-daemon's credentials; pick up local TCPv4 clients' credentials (process ID and security identifier, i.e. user) using GetExtendedTcpTable() (fd.o #61787, Ralf Habacker) D-Bus 1.7.0 (2013-02-22) == The "Disingenuous Assertions" release. This is a new development release, starting the 1.7.x branch. D-Bus 1.6 remains the recommended version for long-term-supported distributions or the upcoming GNOME 3.8 release. Build-time configuration changes: • The --with-dbus-session-bus-default-address configure option is no longer supported. Use the new --with-dbus-session-bus-connect-address and --with-dbus-session-bus-listen-address options instead. On Windows, you usually want them to have the same argument; on Unix, the defaults are usually correct. • Similarly, the DBUS_SESSION_BUS_DEFAULT_ADDRESS CMake variable is no longer supported; use the new DBUS_SESSION_BUS_LISTEN_ADDRESS and DBUS_SESSION_BUS_CONNECT_ADDRESS variables instead. • cmake/cross-compile.sh has been removed. Instead, please use a cross-toolchain file (-DCMAKE_TOOLCHAIN_FILE) as documented at ; or use Autotools as documented in "info automake Cross-Compilation", and set PKG_CONFIG_PATH appropriately. Requirements: • Man pages now require xmlto (or either xmlto or meinproc, if using CMake). • man2html is no longer used. Enhancements: • D-Bus Specification 0.20 · actually say that /org/freedesktop/DBus is the object that implements o.fd.DBus (fd.o #51865, Colin Walters) · various reorganisation for better clarity (fd.o #38252, Simon McVittie) · stop claiming that all basic types work just like INT32 (strings don't!) • The "source code" for the man pages is now Docbook XML, eliminating the outdated duplicate copies used when building with CMake. (fd.o #59805; Ralf Habacker, Simon McVittie) Fixes: • In the activation helper, when compiled for tests, do not reset the system bus address, fixing the regression tests. (fd.o #52202, Simon) • Fix building with Valgrind 3.8, at the cost of causing harmless warnings with Valgrind 3.6 on some compilers (fd.o #55932, Arun Raghavan) • Merge from system-local.conf if necessary (fd.o #51560, Krzysztof Konopko) • Under CMake, prefer xmlto over meinproc (fd.o #59733, Ralf Habacker) • Stop duplicating CMake's own logic to find libexpat (fd.o #59733, Ralf Habacker) • Don't assume CMake host and build system are the same (fd.o #59733, Ralf Habacker) • Avoid deprecation warnings for GLib 2.35 (fd.o #59971, Simon McVittie) • Unix-specific: · Check for functions in libpthread correctly, fixing compilation on (at least) OpenBSD (fd.o #47239, Simon) · Don't leak temporary fds pointing to /dev/null (fd.o #56927, Michel HERMIER) · Update sd-daemon.[ch] from systemd (fd.o #60681) · Add partial support for QNX (fd.o #60339, fd.o #61176; Matt Fischer) • Windows-specific: · The default session bus listening and connecting address is now "autolaunch:", which makes D-Bus on Windows interoperate with itself and GDBus "out of the box". Use the configure options and cmake variables described above if you require a different autolaunch scope. (fd.o #38201, Simon McVittie) · Avoid a CMake warning under Cygwin (fd.o #59401, Ralf Habacker) • Create session.d, system.d directories under CMake (fd.o #41319, Ralf Habacker) D-Bus 1.6.8 (2012-09-28) == The "Fix one thing, break another" release. • Follow up to CVE-2012-3524: The additional hardening work to use __secure_getenv() as a followup to bug #52202 broke certain configurations of gnome-keyring. Given the difficulty of making this work without extensive changes to gnome-keyring, use of __secure_getenv() is deferred. D-Bus 1.6.6 (2012-09-28) == The "Clear the environment in your setuid binaries, please" release. • CVE-2012-3524: Don't access environment variables (fd.o #52202) Thanks to work and input from Colin Walters, Simon McVittie, Geoffrey Thomas, and others. • Unix-specific: · Fix compilation on Solaris (fd.o #53286, Jonathan Perkin) · Work around interdependent headers on OpenBSD by including sys/types.h before each use of sys/socket.h (fd.o #54418, Brad Smith) D-Bus 1.6.4 (2012-07-18) == • Detect that users are "at the console" correctly when configured with a non-default path such as --enable-console-auth-dir=/run/console (fd.o #51521, Dave Reisner) • Remove an incorrect assertion from DBusTransport (fd.o #51657, Simon McVittie) • Make --enable-developer default to "no" (regression in 1.6.2; fd.o #51657, Simon McVittie) • Windows-specific: · Launch dbus-daemon correctly if its path contains a space (fd.o #49450, Wolfgang Baron) D-Bus 1.6.2 (2012-06-27) == The "Ice Cabbage" release. • Change how we create /var/lib/dbus so it works under Automake >= 1.11.4 (fd.o #51406, Simon McVittie) • Don't return from dbus_pending_call_set_notify with a lock held on OOM (fd.o #51032, Simon McVittie) • Disconnect "developer mode" (assertions, verbose mode etc.) from Automake maintainer mode. D-Bus developers should now configure with --enable-developer. Automake maintainer mode is now on by default; distributions can disable it with --disable-maintainer-mode. (fd.o #34671, Simon McVittie) • Automatically define DBUS_STATIC_BUILD in static-only Autotools builds, fixing linking when targeting Windows (fd.o #33973; william, Simon McVittie) • Unix-specific: · Check for libpthread under CMake on Unix (fd.o #47237, Simon McVittie) D-Bus 1.6.0 (2012-06-05) == The “soul of this machine has improved” release. This version starts a new stable branch of D-Bus: only bug fixes will be accepted into 1.6.x. Other changes will now go to the 1.7.x branch. Summary of changes since 1.4.x: • New requirements · PTHREAD_MUTEX_RECURSIVE on Unix · compiler support for 64-bit integers (int64_t or equivalent) • D-Bus Specification v0.19 • New dbus-daemon features · rules allow the service to own names like com.example.Service.Instance3 · optional systemd integration when checking at_console policies · --nopidfile option, mainly for use by systemd · path_namespace and arg0namespace may appear in match rules · eavesdropping is disabled unless the match rule contains eavesdrop=true • New public API · functions to validate various string types (dbus_validate_path() etc.) · dbus_type_is_valid() · DBusBasicValue, a union of every basic type • Bug fixes · removed an unsafe reimplementation of recursive mutexes · dbus-daemon no longer busy-loops if it has far too many file descriptors · dbus-daemon.exe --print-address works on Windows · all the other bug fixes from 1.4.20 • Other major implementation changes · on Linux, dbus-daemon uses epoll if supported, for better scalability · dbus_threads_init() ignores its argument and behaves like dbus_threads_init_default() instead · removed the per-connection link cache, improving dbus-daemon performance • Developer features · optional Valgrind instrumentation (--with-valgrind) · optional Stats interface on the dbus-daemon (--enable-stats) · optionally abort whenever malloc() fails (--enable-embedded-tests and export DBUS_MALLOC_CANNOT_FAIL=1) Changes since 1.5.12: • Be more careful about monotonic time vs. real time, fixing DBUS_COOKIE_SHA1 spec-compliance (fd.o #48580, David Zeuthen) • Don't use install(1) within the source/build trees, fixing the build as non-root when using OpenBSD install(1) (fd.o #48217, Antoine Jacoutot) • Add missing commas in some tcp and nonce-tcp addresses, and remove an unused duplicate copy of the nonce-tcp transport in Windows builds (fd.o #45896, Simon McVittie) D-Bus 1.5.12 (2012-03-27) == The “Big Book of Science” release. • Add public API to validate various string types: dbus_validate_path(), dbus_validate_interface(), dbus_validate_member(), dbus_validate_error_name(), dbus_validate_bus_name(), dbus_validate_utf8() (fd.o #39549, Simon McVittie) • Turn DBusBasicValue into public API so bindings don't need to invent their own "union of everything" type (fd.o #11191, Simon McVittie) • Enumerate data files included in the build rather than using find(1) (fd.o #33840, Simon McVittie) • Add support for policy rules like in dbus-daemon (fd.o #46273, Alban Crequy) • Windows-specific: · make dbus-daemon.exe --print-address (and --print-pid) work again on Win32, but not on WinCE (fd.o #46049, Simon McVittie) · fix duplicate case value when compiling against mingw-w64 (fd.o #47321, Andoni Morales Alastruey) D-Bus 1.5.10 (2012-02-21) == The "fire in Delerium" release. On Unix platforms, PTHREAD_MUTEX_RECURSIVE (as specified in POSIX 2008 Base and SUSv2) is now required. • D-Bus Specification 0.19: · Formally define unique connection names and well-known bus names, and document best practices for interface, bus, member and error names, and object paths (fd.o #37095, Simon McVittie) · Document the search path for session and system services on Unix, and where they should be installed by build systems (fd.o #21620, fd.o #35306; Simon McVittie) · Document the systemd transport (fd.o #35232, Lennart Poettering) • Make dbus_threads_init() use the same built-in threading implementation as dbus_threads_init_default(); the user-specified primitives that it takes as a parameter are now ignored (fd.o #43744, Simon McVittie) • Allow all configured auth mechanisms, not just one (fd.o #45106, Pavel Strashkin) • Improve cmake build system (Ralf Habacker): · simplify XML parser dependencies (fd.o #41027) · generate build timestamp (fd.o #41029) · only create batch files on Windows · fix option and cache syntax · add help-options target · share dbus-arch-deps.h.in with autotools rather than having our own version (fd.o #41033) • Build tests successfully with older GLib, as found in e.g. Debian 6 (fd.o #41219, Simon McVittie) • Avoid use of deprecated GThread API (fd.o #44413, Martin Pitt) • Build documentation correctly if man2html doesn't support filenames on its command-line (fd.o #43875, Jack Nagel) • Improve test coverage. To get even more coverage, run the tests with DBUS_TEST_SLOW=1 (fd.o #38285, #42811; Simon McVittie) • Reduce the size of the shared library by moving functionality only used by dbus-daemon, tests etc. into their internal library and deleting unused code (fd.o #34976, #39759; Simon McVittie) • Add dbus-daemon --nopidfile option, overriding the configuration, for setups where the default configuration must include to avoid breaking traditional init, but the pid file is in fact unnecessary; use it under systemd to improve startup time a bit (fd.o #45520, Lennart Poettering) • Optionally (if configured --with-valgrind) add instrumentation to debug libdbus and associated tools more meaningfully under Valgrind (fd.o #37286, Simon McVittie) • Improve the dbus-send(1) man page (fd.o #14005, Simon McVittie) • Make dbus-protocol.h compatible with C++11 (fd.o #46147, Marc Mutz) • If tests are enabled and DBUS_MALLOC_CANNOT_FAIL is set in the environment, abort on failure to malloc() (like GLib does), to turn runaway memory leaks into a debuggable core-dump if a resource limit is applied (fd.o #41048, Simon McVittie) • Don't crash if realloc() returns NULL in a debug build (fd.o #41048, Simon McVittie) • Unix-specific: · Replace our broken reimplementation of recursive mutexes, which has been broken since 2006, with an ordinary pthreads recursive mutex (fd.o #43744; Sigmund Augdal, Simon McVittie) · Use epoll(7) for a more efficient main loop in Linux; equivalent patches welcomed for other OSs' equivalents like kqueue, /dev/poll, or Solaris event ports (fd.o #33337; Simon McVittie, Ralf Habacker) · When running under systemd, use it instead of ConsoleKit to check whether to apply at_console policies (fd.o #39609, Lennart Poettering) · Avoid a highly unlikely fd leak (fd.o #29881, Simon McVittie) · Don't close invalid fd -1 if getaddrinfo fails (fd.o #37258, eXeC001er)   · Don't touch ~/.dbus and ~/.dbus-keyrings when running 'make installcheck' (fd.o #41218, Simon McVittie) · Stop pretending we respect XDG_DATA_DIRS for system services: the launch helper doesn't obey environment variables to avoid privilege escalation attacks, so make the system bus follow the same rules (fd.o #21620, Simon McVittie) • Windows-specific: · Find the dbus-daemon executable next to the shared library (fd.o #41558; Jesper Dam, Ralf Habacker) · Remove the faulty implementation of _dbus_condvar_wake_all (fd.o #44609, Simon McVittie) D-Bus 1.5.8 (2011-09-21) == The "cross-metering" release. In addition to dead code removal and refactoring, this release contains all of the bugfixes from 1.4.16. • Clean up dead code, and make more warnings fatal in development builds (fd.o #39231, fd.o #41012; Simon McVittie) • If full test coverage is requested via --enable-tests, strictly require Python, pygobject and dbus-python, which are required by some tests; if not, and Python is missing, skip those tests rather than failing (fd.o #37847, Simon McVittie) • When using cmake, provide the same version-info API in the installed headers as for autotools (DBUS_VERSION, etc.) (fd.o #40905, Ralf Habacker) • Add a regression test for fd.o #38005 (fd.o #39836, Simon McVittie) • Make "NOCONFIGURE=1 ./autogen.sh" not run configure (Colin Walters) • Add _DBUS_STATIC_ASSERT and use it to check invariants (fd.o #39636, Simon McVittie) • Fix duplicates in authors list (Ralf Habacker) • Fix broken links from dbus-tutorial.html if $(htmldir) != $(docdir) (fd.o #39879, Chris Mayo) • Fix a small memory leak, and a failure to report errors, when updating a service file entry for activation (fd.o #39230, Simon McVittie) • Unix-specific: · Clean up (non-abstract) Unix sockets on bus daemon exit (fd.o #38656; Brian Cameron, Simon McVittie) · On systems that use libcap-ng but not systemd, drop supplemental groups when switching to the daemon user (Red Hat #726953, Steve Grubb) · Make the cmake build work again on GNU platforms (fd.o #29228, Simon McVittie) · Fix compilation on non-C99 systems that have inttypes.h but not stdint.h, like Solaris (fd.o #40313, Dagobert Michelsen) · Define CMSG_ALIGN, CMSG_LEN, CMSG_SPACE on Solaris < 10 (fd.o #40235, Simon McVittie) · Cope with Unixes that don't have LOG_PERROR, like Solaris 10 (fd.o #39987, Simon McVittie) · Cope with platforms whose vsnprintf violates both POSIX and C99, like Tru64, IRIX and HP-UX (fd.o #11668, Simon McVittie) • Windows-specific: · Fix compilation on MSVC, which doesn't understand "inline" with its C99 meaning (fd.o #40000; Ralf Habacker, Simon McVittie) · Fix misuse of GPid in test/dbus-daemon.c (fd.o #40003, Simon McVittie) · Fix cross-compilation to Windows with Automake (fd.o #40003, Simon McVittie) D-Bus 1.5.6 (2011-07-29) == The "weird, gravy-like aftertaste" release. In addition to new features and refactoring, this release contains all of the bugfixes from 1.4.14. Potentially incompatible (Bustle and similar debugging tools will need changes to work as intended): • Do not allow match rules to "eavesdrop" (receive messages intended for a different recipient) by mistake: eavesdroppers must now opt-in to this behaviour by putting "eavesdrop='true'" in the match rule, which will not have any practical effect on buses where eavesdropping is not allowed (fd.o #37890, Cosimo Alfarano) Other changes: • D-Bus Specification version 0.18 (fd.o #37890, fd.o #39450, fd.o #38252; Cosimo Alfarano, Simon McVittie) · add the "eavesdrop" keyword to match rules · define eavesdropping, unicast messages and broadcast messages · stop claiming that match rules are needed to match unicast messages to you · promote the type system to be a top-level section • Use DBUS_ERROR_OBJECT_PATH_IN_USE if dbus_connection_try_register_object_path or dbus_connection_try_register_fallback fails, not ...ADDRESS_IN_USE, and simplify object-path registration (fd.o #38874, Jiří Klimeš) • Consistently use atomic operations on everything that is ever manipulated via atomic ops, as was done for changes to DBusConnection's refcount in 1.4.12 (fd.o #38005, Simon McVittie) • Fix a file descriptor leak when connecting to a TCP socket (fd.o #37258, Simon McVittie) • Make "make check" in a clean tree work, by not running tests until test data has been set up (fd.o #34405, Simon McVittie) • The dbus-daemon no longer busy-loops if it has a very large number of file descriptors (fd.o #23194, Simon McVittie) • Refactor message flow through dispatching to avoid locking violations if the bus daemon's message limit is hit; remove the per-connection link cache, which was meant to improve performance, but now reduces it (fd.o #34393, Simon McVittie) • Some cmake fixes (Ralf Habacker) • Remove dead code, mainly from DBusString (fd.o #38570, fd.o #39610; Simon McVittie, Lennart Poettering) • Stop storing two extra byte order indicators in each D-Bus message (fd.o #38287, Simon McVittie) • Add an optional Stats interface which can be used to get statistics from a running dbus-daemon if enabled at configure time with --enable-stats (fd.o #34040, Simon McVittie) • Fix various typos (fd.o #27227, fd.o #38284; Sascha Silbe, Simon McVittie) • Documentation (fd.o #36156, Simon McVittie): · let xsltproc be overridden as usual: ./configure XSLTPROC=myxsltproc · install more documentation automatically, including man2html output · put dbus.devhelp in the right place (it must go in ${htmldir}) • Unix-specific: · look for system services in /lib/dbus-1/system-services in addition to all the other well-known locations; note that this should always be /lib, even on platforms where shared libraries on the root FS would go in /lib64, /lib/x86_64-linux-gnu or similar (fd.o #35229, Lennart Poettering) · opt-in to fd passing on Solaris (fd.o #33465, Simon McVittie) • Windows-specific (Ralf Habacker): · fix use of a mutex for autolaunch server detection · don't crash on malloc failure in _dbus_printf_string_upper_bound D-Bus 1.5.4 (2011-06-10) == Security (local denial of service): • Byte-swap foreign-endian messages correctly, preventing a long-standing local DoS if foreign-endian messages are relayed through the dbus-daemon (backporters: this is git commit c3223ba6c401ba81df1305851312a47c485e6cd7) (CVE-2011-2200, fd.o #38120, Debian #629938; Simon McVittie) New things: • The constant to use for an infinite timeout now has a name, DBUS_TIMEOUT_INFINITE. It is numerically equivalent to 0x7fffffff (INT32_MAX) which can be used for source compatibility with older versions of libdbus. • If GLib and DBus-GLib are already installed, more tests will be built, providing better coverage. The new tests can also be installed via ./configure --enable-installed-tests for system integration testing, if required. (fd.o #34570, Simon McVittie) Changes: • Consistently use atomic operations for the DBusConnection's refcount, fixing potential threading problems (fd.o #38005, Simon McVittie) • Don't use -Wl,--gc-sections by default: in practice the size decrease is small (300KiB on x86-64) and it frequently doesn't work in unusual toolchains. To optimize for minimum installed size, you should benchmark various possibilities for CFLAGS and LDFLAGS, and set the best flags for your particular toolchain at configure time. (fd.o #33466, Simon McVittie) • Use #!/bin/sh for run-with-tmp-session-bus.sh, making it work on *BSD (fd.o #35880, Timothy Redaelli) • Use ln -fs to set up dbus for systemd, which should fix reinstallation when not using a DESTDIR (fd.o #37870, Simon McVittie) • Windows-specific changes: · don't try to build dbus-daemon-launch-helper (fd.o #37838, Mark Brand) D-Bus 1.5.2 (2011-06-01) == The "Boar Hunter" release. Notes for distributors: This version of D-Bus no longer uses -fPIE by default. Distributions wishing to harden the dbus-daemon and dbus-launch-helper can re-enable this if their toolchain supports it reliably, via something like: ./configure CFLAGS=-fPIE LDFLAGS="-pie -Wl,-z,relro" or by using distribution-specific wrappers such as Debian's hardening-wrapper. Changes: • D-Bus Specification v0.17 · Reserve the extra characters used in signatures by GVariant (fd.o #34529, Simon McVittie) · Define the ObjectManager interface (fd.o #34869, David Zeuthen) • Don't force -fPIE: distributions and libtool know better than we do whether it's desirable (fd.o #16621, fd.o #27215; Simon McVittie) • Allow --disable-gc-sections, in case your toolchain offers the -ffunction-sections, -fdata-sections and -Wl,--gc-sections options but they're broken, as seen on Solaris (fd.o #33466, Simon McVittie) • Install dbus-daemon and dbus-daemon-launch-helper in a more normal way (fd.o #14512; Simon McVittie, loosely based on a patch from Luca Barbato) • Ensure that maintainers upload documentation with the right permissions (fd.o #36130, Simon McVittie) • Don't force users of libdbus to be linked against -lpthread, -lrt (fd.o #32827, Simon McVittie) • Log system-bus activation information to syslog (fd.o #35705, Colin Walters) • Log messages dropped due to quotas to syslog (fd.o #35358, Simon McVittie) • Make the nonce-tcp transport work on Unix (fd.o #34569, Simon McVittie) • On Unix, if /var/lib/dbus/machine-id cannot be read, try /etc/machine-id (fd.o #35228, Lennart Poettering) • In the regression tests, don't report fds as "leaked" if they were open on startup (fd.o #35173, Simon McVittie) • Make dbus-monitor bail out if asked to monitor more than one bus, rather than silently using the last one (fd.o #26548, Will Thompson) • Clarify documentation (fd.o #35182, Simon McVittie) • Clean up minor dead code and some incorrect error handling (fd.o #33128, fd.o #29881; Simon McVittie) • Check that compiler options are supported before using them (fd.o #19681, Simon McVittie) • Windows: • Remove obsolete workaround for winioctl.h (fd.o #35083, Ralf Habacker) D-Bus 1.5.0 (2011-04-11) == The "you never know when you need to tow something from your giant flying shark" release. • D-Bus Specification v0.16 · Add support for path_namespace and arg0namespace in match rules (fd.o #24317, #34870; Will Thompson, David Zeuthen, Simon McVittie) · Make argNpath support object paths, not just object-path-like strings, and document it better (fd.o #31818, Will Thompson) • Let the bus daemon implement more than one interface (fd.o #33757, Simon McVittie) • Optimize _dbus_string_replace_len to reduce waste (fd.o #21261, Roberto Guido) • Require user intervention to compile with missing 64-bit support (fd.o #35114, Simon McVittie) • Add dbus_type_is_valid as public API (fd.o #20496, Simon McVittie) • Raise UnknownObject instead of UnknownMethod for calls to methods on paths that are not part of the object tree, and UnknownInterface for calls to unknown interfaces in the bus daemon (fd.o #34527, Lennart Poettering) D-Bus 1.4.8 (2011-04-08) == The "It's like the beginning of a lobster" release. • Rename configure.in to configure.ac, and update it to modern conventions (fd.o #32245; Javier Jardón, Simon McVittie) • Correctly give XDG_DATA_HOME priority over XDG_DATA_DIRS (fd.o #34496, Anders Kaseorg) • Prevent X11 autolaunching if $DISPLAY is unset or empty, and add --disable-x11-autolaunch configure option to prevent it altogether in embedded environments (fd.o #19997, NB#219964; Simon McVittie) • Install the documentation, and an index for Devhelp (fd.o #13495, Debian #454142; Simon McVittie, Matthias Clasen) • If checks are not disabled, check validity of string-like types and booleans when sending them (fd.o #16338, NB#223152; Simon McVittie) • Add UnknownObject, UnknownInterface, UnknownProperty and PropertyReadOnly errors to dbus-shared.h (fd.o #34527, Lennart Poettering) • Break up a huge conditional in config-parser so gcov can produce coverage data (fd.o #10887, Simon McVittie) • List which parts of the Desktop Entry specification are applicable to .service files (fd.o #19159, Sven Herzberg) • Don't suppress service activation if two services have the same Exec= (fd.o #35750, Colin Walters) • Windows: · Avoid the name ELEMENT_TYPE due to namespace-pollution from winioctl.h (Andre Heinecke) · Include _dbus_path_is_absolute in libdbus on Windows, fixing compilation (fd.o #32805, Mark Brand) D-Bus 1.4.6 (2010-02-17) == The "1, 2, miss a few, 99, 100" release. • Remove unfinished changes intended to support GTest-based tests, which were mistakenly included in 1.4.4 D-Bus 1.4.4 (2010-02-17) == • Switch back to using even micro versions for stable releases; 1.4.1 should have been called 1.4.2, so skip that version number • Don't leave bad file descriptors being watched when spawning processes, which could result in a busy-loop (fd.o #32992, NB#200248; possibly also LP#656134, LP#680444, LP#713157) • Check for MSG_NOSIGNAL correctly • Fix failure to detect abstract socket support (fd.o #29895) • Make _dbus_system_logv actually exit with DBUS_SYSTEM_LOG_FATAL (fd.o #32262, NB#180486) • Improve some error code paths (fd.o #29981, fd.o #32264, fd.o #32262, fd.o #33128, fd.o #33277, fd.o #33126, NB#180486) • Avoid possible symlink attacks in /tmp during compilation (fd.o #32854) • Tidy up dead code (fd.o #25306, fd.o #33128, fd.o #34292, NB#180486) • Improve gcc malloc annotations (fd.o #32710) • If the system bus is launched via systemd, protect it from the OOM killer • Documentation improvements (fd.o #11190) • Avoid readdir_r, which is difficult to use correctly (fd.o #8284, fd.o #15922, LP#241619) • Cope with invalid files in session.d, system.d (fd.o #19186, Debian #230231) • Don't distribute generated files that embed our builddir (fd.o #30285, fd.o #34292) • Raise the system bus's fd limit to be sufficient for its configuration (fd.o #33474, LP#381063) • Fix syslog string processing • Ignore -Waddress • Remove broken gcov parsing code and --enable-gcov, and replace them with lcov HTML reports and --enable-compiler-coverage (fd.o #10887) • Windows: · avoid live-lock in Windows CE due to unfair condition variables • OpenBSD: · support credentials-passing (fd.o #32542) • Solaris: · opt-in to thread safety (fd.o #33464) D-Bus 1.4.1 (20 December 2010) == • Fix for CVE-2010-4352: sending messages with excessively-nested variants can crash the bus. The existing restriction to 64-levels of nesting previously only applied to the static type signature; now it also applies to dynamic nesting using variants. Thanks to Rémi Denis-Courmont for discoving this issue. • OS X portability fixes, including launchd support. • Windows autolaunch improvements. • Various bug fixes. D-Bus 1.4.0 (6 Sep 2010) == - systemd hookup D-Bus 1.3.1 (23 June 2010) == - New standardized PropertiesChanged signal in the properties interface - Various portability fixes, in particular to Windows platforms - Support forking bus services, for compatibility D-Bus 1.3.0 (29 July 2009) == - ability for dbus-send to send to any bus (--address) - file descriptor passing on Unix socket transports - use of GCC atomic intrinsics for better processor support (requires -march=i486 or above for x86 compilation) - thread-safe FD_CLOEXEC setting on recent Linux kernels (2.6.24-27 and up) and glibc (2.9 for pipe2 and 2.10 for accept4) - feature negotiation in the bus daemon dbus-1.10.6/INSTALL0000644000175000017500000002333312602773110013572 0ustar00smcvsmcv00000000000000 DBus Installation ================= Quick start =========== DBus could be build with GNU AutoTools or with cmake for its build system, thus the basic install procedure can be summarized as: with autotools: ./configure --prefix=/usr make su make install The configure script will automatically determine whether to try and build bindings for GLib, Qt, Qt3, Python and Mono based on what tools are installed on the host system. The default build behaviour can be overridden using the --enable-XXX/--disable-XXX arguments to configure. A typical scenario in which it is desirable to override automatic detection, is during packaging of binary builds, where a predictable dependancy chain is required. For more details on GNU AutoTools installation, consult the generic instructions later in this document with cmake: mkdir dbus-build-dir cd dbus-build-dir cmake -G [-D