e0e75c0fc20d30a90c39fcecf8f71198a73e917d
[platform/upstream/syncevolution.git] / src / dbus / server / server.h
1 /*
2  * Copyright (C) 2011 Intel Corporation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) version 3.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301  USA
18  */
19
20 #ifndef SYNCEVO_DBUS_SERVER_H
21 #define SYNCEVO_DBUS_SERVER_H
22
23 #include <set>
24
25 #include <boost/shared_ptr.hpp>
26 #include <boost/weak_ptr.hpp>
27 #include <boost/signals2.hpp>
28
29 #include <syncevo/SyncConfig.h>
30
31 #include "exceptions.h"
32 #include "auto-term.h"
33 #include "timeout.h"
34 #include "dbus-callbacks.h"
35 #include "read-operations.h"
36
37 #include <syncevo/declarations.h>
38 SE_BEGIN_CXX
39
40 class Resource;
41 class Session;
42 class Server;
43 class InfoReq;
44 class BluezManager;
45 class Restart;
46 class Client;
47 class GLibNotify;
48 class AutoSyncManager;
49 class PresenceStatus;
50 class ConnmanClient;
51 class NetworkManagerClient;
52
53 // TODO: avoid polluting namespace
54 using namespace std;
55
56 /**
57  * Implements the main org.syncevolution.Server interface.
58  *
59  * The Server class is responsible for listening to clients and
60  * spinning of sync sessions as requested by clients.
61  */
62 class Server : public GDBusCXX::DBusObjectHelper,
63                public LoggerBase
64 {
65     GMainLoop *m_loop;
66     bool &m_shutdownRequested;
67     Timespec m_lastFileMod;
68     boost::shared_ptr<SyncEvo::Restart> &m_restart;
69
70     uint32_t m_lastSession;
71     typedef std::list< std::pair< boost::shared_ptr<GDBusCXX::Watch>, boost::shared_ptr<Client> > > Clients_t;
72     Clients_t m_clients;
73
74     /**
75      * Functor will never be called, important are the shared pointers
76      * bound to it. m_delayDeletion will be cleared in idle and when
77      * server terminates, thus unrefing anything encapsulated inside
78      * it.
79      */
80     std::list< boost::function<void ()> > m_delayDeletion;
81
82     /**
83      * Watch all files mapped into our address space. When
84      * modifications are seen (as during a package upgrade), sets
85      * m_shutdownRequested. This prevents adding new sessions and
86      * prevents running already queued ones, because future sessions
87      * might not be able to execute correctly without a restart. For example, a
88      * sync with libsynthesis from 1.1 does not work with
89      * SyncEvolution XML files from 1.2. The daemon then waits
90      * for the changes to settle (see SHUTDOWN_QUIESENCE_SECONDS) and either shuts
91      * down or restarts.  The latter is necessary if the daemon has
92      * automatic syncing enabled in a config.
93      */
94     list< boost::shared_ptr<GLibNotify> > m_files;
95     void fileModified();
96     bool shutdown();
97
98     /**
99      * timer which counts seconds until server is meant to shut down
100      */
101     Timeout m_shutdownTimer;
102
103
104     /**
105      * The session which currently holds the main lock on the server.
106      * To avoid issues with concurrent modification of data or configs,
107      * only one session may make such modifications at a time. A
108      * plain pointer which is reset by the session's deconstructor.
109      *
110      * The server doesn't hold a shared pointer to the session so
111      * that it can be deleted when the last client detaches from it.
112      *
113      * A weak pointer alone did not work because it does not provide access
114      * to the underlying pointer after the last corresponding shared
115      * pointer is gone (which triggers the deconstructing of the session).
116      */
117     Session *m_activeSession;
118
119     /**
120      * The weak pointer that corresponds to m_activeSession.
121      */
122     boost::weak_ptr<Session> m_activeSessionRef;
123
124     /**
125      * The running sync session. Having a separate reference to it
126      * ensures that the object won't go away prematurely, even if all
127      * clients disconnect.
128      *
129      * The session itself needs to request this special treatment with
130      * addSyncSession() and remove itself with removeSyncSession() when
131      * done.
132      */
133     boost::shared_ptr<Session> m_syncSession;
134
135     typedef std::list< boost::weak_ptr<Session> > WorkQueue_t;
136     /**
137      * A queue of pending, idle Sessions. Sorted by priority, most
138      * important one first. Currently this is used to give client
139      * requests a boost over remote connections and (in the future)
140      * automatic syncs.
141      *
142      * Active sessions are removed from this list and then continue
143      * to exist as long as a client in m_clients references it or
144      * it is the currently running sync session (m_syncSession).
145      */
146     WorkQueue_t m_workQueue;
147
148     /**
149      * a hash of pending InfoRequest
150      */
151     typedef std::map<string, boost::weak_ptr<InfoReq> > InfoReqMap;
152
153     // hash map of pending info requests
154     InfoReqMap m_infoReqMap;
155
156     // the index of last info request
157     uint32_t m_lastInfoReq;
158
159     // a hash to represent matched templates for devices, the key is
160     // the peer name
161     typedef std::map<string, boost::shared_ptr<SyncConfig::TemplateDescription> > MatchedTemplates;
162
163     MatchedTemplates m_matchedTempls;
164
165     boost::shared_ptr<BluezManager> m_bluezManager;
166
167     /** devices which have sync services */
168     SyncConfig::DeviceList m_syncDevices;
169
170     /**
171      * Watch callback for a specific client or connection.
172      */
173     void clientGone(Client *c);
174
175
176  public:
177     // D-Bus API, also usable directly
178
179     /** Server.GetCapabilities() */
180     vector<string> getCapabilities();
181
182     /** Server.GetVersions() */
183     StringMap getVersions();
184
185     /** Server.Attach() */
186     void attachClient(const GDBusCXX::Caller_t &caller,
187                       const boost::shared_ptr<GDBusCXX::Watch> &watch);
188
189     /** Server.Detach() */
190     void detachClient(const GDBusCXX::Caller_t &caller);
191
192     /** Server.DisableNotifications() */
193     void disableNotifications(const GDBusCXX::Caller_t &caller,
194                               const string &notifications) {
195         setNotifications(false, caller, notifications);
196     }
197
198     /** Server.EnableNotifications() */
199     void enableNotifications(const GDBusCXX::Caller_t &caller,
200                              const string &notifications) {
201         setNotifications(true, caller, notifications);
202     }
203
204     /** Server.NotificationAction() */
205     void notificationAction(const GDBusCXX::Caller_t &caller) {
206         pid_t pid;
207         if((pid = fork()) == 0) {
208             // search sync-ui from $PATH
209             execlp("sync-ui", "sync-ui", (const char*)0);
210
211             // Failing that, try meego-ux-settings/Sync
212             execlp("meego-qml-launcher",
213               "meego-qml-launcher",
214               "--opengl", "--fullscreen", "--app", "meego-ux-settings",
215               "--cmd", "showPage", "--cdata", "Sync", (const char*)0);
216
217             // Failing that, simply exit
218             exit(0);
219         }
220     }
221
222     /** actual implementation of enable and disable */
223     void setNotifications(bool enable,
224                           const GDBusCXX::Caller_t &caller,
225                           const string &notifications);
226
227     /** Server.Connect() */
228     void connect(const GDBusCXX::Caller_t &caller,
229                  const boost::shared_ptr<GDBusCXX::Watch> &watch,
230                  const StringMap &peer,
231                  bool must_authenticate,
232                  const std::string &session,
233                  GDBusCXX::DBusObject_t &object);
234
235     /** Server.StartSession() */
236     void startSession(const GDBusCXX::Caller_t &caller,
237                       const boost::shared_ptr<GDBusCXX::Watch> &watch,
238                       const std::string &server,
239                       GDBusCXX::DBusObject_t &object) {
240         startSessionWithFlags(caller, watch, server, std::vector<std::string>(), object);
241     }
242
243     /** Server.StartSessionWithFlags() */
244     void startSessionWithFlags(const GDBusCXX::Caller_t &caller,
245                                const boost::shared_ptr<GDBusCXX::Watch> &watch,
246                                const std::string &server,
247                                const std::vector<std::string> &flags,
248                                GDBusCXX::DBusObject_t &object);
249
250     /** internal representation of D-Bus API Server.StartSessionWithFlags() */
251     enum SessionFlags {
252         SESSION_FLAG_NONE = 0,
253         SESSION_FLAG_NO_SYNC = 1<<0,
254         SESSION_FLAG_ALL_CONFIGS = 1<<1
255     };
256
257     /**
258      * Creates a session, queues it, then invokes the callback
259      * once the session is active. The caller is responsible
260      * for holding a reference to the session. If it drops
261      * that reference, the session gets deleted and the callback
262      * will not be called.
263      */
264     boost::shared_ptr<Session> startInternalSession(const std::string &server,
265                                                     SessionFlags flags,
266                                                     const boost::function<void (const boost::weak_ptr<Session> &session)> &callback);
267
268     /** Server.GetConfig() */
269     void getConfig(const std::string &config_name,
270                    bool getTemplate,
271                    ReadOperations::Config_t &config)
272     {
273         ReadOperations ops(config_name, *this);
274         ops.getConfig(getTemplate , config);
275     }
276
277     /** Server.GetReports() */
278     void getReports(const std::string &config_name,
279                     uint32_t start, uint32_t count,
280                     ReadOperations::Reports_t &reports)
281     {
282         ReadOperations ops(config_name, *this);
283         ops.getReports(start, count, reports);
284     }
285
286     /** Server.CheckSource() */
287     void checkSource(const std::string &configName,
288                      const std::string &sourceName)
289     {
290         ReadOperations ops(configName, *this);
291         ops.checkSource(sourceName);
292     }
293
294     /** Server.GetDatabases() */
295     void getDatabases(const std::string &configName,
296                       const string &sourceName,
297                       ReadOperations::SourceDatabases_t &databases)
298     {
299         ReadOperations ops(configName, *this);
300         ops.getDatabases(sourceName, databases);
301     }
302
303     /** Server.GetConfigs() */
304     void getConfigs(bool getTemplates,
305                     std::vector<std::string> &configNames)
306     {
307         ReadOperations ops("", *this);
308         ops.getConfigs(getTemplates, configNames);
309     }
310
311     /** Server.CheckPresence() */
312     void checkPresence(const std::string &server,
313                        std::string &status,
314                        std::vector<std::string> &transports);
315
316     /** Server.GetSessions() */
317     void getSessions(std::vector<GDBusCXX::DBusObject_t> &sessions);
318
319     /** Server.InfoResponse() */
320     void infoResponse(const GDBusCXX::Caller_t &caller,
321                       const std::string &id,
322                       const std::string &state,
323                       const std::map<string, string> &response);
324
325     /** Server.SessionChanged */
326     GDBusCXX::EmitSignal2<const GDBusCXX::DBusObject_t &,
327                 bool> sessionChanged;
328
329     /** Server.PresenceChanged */
330     GDBusCXX::EmitSignal3<const std::string &,
331                 const std::string &,
332                 const std::string &> presence;
333
334     /**
335      * Server.TemplatesChanged, triggered each time m_syncDevices, the
336      * input for the templates, is changed
337      */
338     GDBusCXX::EmitSignal0 templatesChanged;
339
340     /**
341      * Server.ConfigChanged, triggered each time a session ends
342      * which modified its configuration
343      */
344     GDBusCXX::EmitSignal0 configChanged;
345
346     /** Server.InfoRequest */
347     GDBusCXX::EmitSignal6<const std::string &,
348                           const GDBusCXX::DBusObject_t &,
349                           const std::string &,
350                           const std::string &,
351                           const std::string &,
352                           const std::map<string, string> &> infoRequest;
353
354     /** wrapper around Server.LogOutput, filters  by DBusLogLevel */
355     void logOutput(const GDBusCXX::DBusObject_t &path,
356                    Logger::Level level,
357                    const std::string &explanation,
358                    const std::string &procname);
359
360     void setDBusLogLevel(Logger::Level level) { m_dbusLogLevel = level; }
361     Logger::Level getDBusLogLevel() const { return m_dbusLogLevel; }
362
363  private:
364     /** Server.LogOutput */
365     GDBusCXX::EmitSignal4<const GDBusCXX::DBusObject_t &,
366                           const std::string &,
367                           const std::string &,
368                           const std::string &> m_logOutputSignal;
369
370     friend class InfoReq;
371
372     /** emit InfoRequest */
373     void emitInfoReq(const InfoReq &);
374
375     /** get the next id of InfoRequest */
376     std::string getNextInfoReq();
377
378     /** remove InfoReq from hash map */
379     void removeInfoReq(const std::string &infoReqId);
380
381     boost::scoped_ptr<PresenceStatus> m_presence;
382     boost::scoped_ptr<ConnmanClient> m_connman;
383     boost::scoped_ptr<NetworkManagerClient> m_networkManager;
384
385     /** Manager to automatic sync */
386     boost::shared_ptr<AutoSyncManager> m_autoSync;
387
388     //automatic termination
389     AutoTerm m_autoTerm;
390
391     // The level of detail for D-Bus logging signals.
392     Logger::Level m_dbusLogLevel;
393
394     //records the parent logger, dbus server acts as logger to
395     //send signals to clients and put logs in the parent logger.
396     LoggerBase &m_parentLogger;
397
398     /**
399      * All active timeouts created by addTimeout().
400      * Each timeout which requests to be not called
401      * again will be removed from this list.
402      */
403     list< boost::shared_ptr<Timeout> > m_timeouts;
404
405     /**
406      * called each time a timeout triggers,
407      * removes those which are done
408      */
409     bool callTimeout(const boost::shared_ptr<Timeout> &timeout, const boost::function<void ()> &callback);
410
411     /** called 1 minute after last client detached from a session */
412     static void sessionExpired(const boost::shared_ptr<Session> &session);
413
414 public:
415     Server(GMainLoop *loop,
416            bool &shutdownRequested,
417            boost::shared_ptr<Restart> &restart,
418            const GDBusCXX::DBusConnectionPtr &conn,
419            int duration);
420     void activate();
421     ~Server();
422
423     /** access to the GMainLoop reference used by this Server instance */
424     GMainLoop *getLoop() { return m_loop; }
425
426     /** process D-Bus calls until the server is ready to quit */
427     void run();
428
429     /** currently running operation */
430     boost::shared_ptr<Session> getSyncSession() const { return m_syncSession; }
431
432     /** true iff no work is pending */
433     bool isIdle() const { return !m_activeSession && m_workQueue.empty(); }
434
435     /** isIdle() might have changed its value, current value included */
436     typedef boost::signals2::signal<void (bool isIdle)> IdleSignal_t;
437     IdleSignal_t m_idleSignal;
438
439     /**
440      * More specific "config changed signal", called with normalized
441      * config name as parameter. Config name is empty if all configs
442      * were affected.
443      */
444     typedef boost::signals2::signal<void (const std::string &configName)> ConfigChangedSignal_t;
445     ConfigChangedSignal_t m_configChangedSignal;
446
447     /**
448      * Called when a session starts its real work (= calls addSyncSession()).
449      */
450     typedef boost::signals2::signal<void (const boost::shared_ptr<Session> &)> NewSyncSessionSignal_t;
451     NewSyncSessionSignal_t m_newSyncSessionSignal;
452
453     /**
454      * look up client by its ID
455      */
456     boost::shared_ptr<Client> findClient(const GDBusCXX::Caller_t &ID);
457
458     /**
459      * find client by its ID or create one anew
460      */
461     boost::shared_ptr<Client> addClient(const GDBusCXX::Caller_t &ID,
462                                         const boost::shared_ptr<GDBusCXX::Watch> &watch);
463
464     /** detach this resource from all clients which own it */
465     void detach(Resource *resource);
466
467     /**
468      * Enqueue a session. Might also make it ready immediately,
469      * if nothing else is first in the queue. To be called
470      * by the creator of the session, *after* the session is
471      * ready to run.
472      */
473     void enqueue(const boost::shared_ptr<Session> &session);
474
475     /**
476      * Remove all sessions with this device ID from the
477      * queue. If the active session also has this ID,
478      * the session will be aborted and/or deactivated.
479      *
480      * Has to be asynchronous because it might involve ensuring that
481      * there is no running helper for this device ID, which requires
482      * communicating with the helper.
483      */
484     void killSessionsAsync(const std::string &peerDeviceID,
485                            const SimpleResult &result);
486
487     /**
488      * Remove a session from the work queue. If it is running a sync,
489      * it will keep running and nothing will change. Otherwise, if it
490      * is "ready" (= holds a lock on its configuration), then release
491      * that lock.
492      */
493     void dequeue(Session *session);
494
495     /**
496      * Remember that the session is running a sync (or some other
497      * important operation) and keeps a pointer to it, to prevent
498      * deleting it. Currently can only called by the active sync
499      * session. Will fail if all clients have detached already.
500      *
501      * If successful, it triggers m_newSyncSessionSignal.
502      */
503     void addSyncSession(Session *session);
504
505     /**
506      * Session is done, ready to be deleted again.
507      */
508     void removeSyncSession(Session *session);
509
510     /**
511      * Checks whether the server is ready to run another session
512      * and if so, activates the first one in the queue.
513      */
514     void checkQueue();
515
516     /**
517      * Special behavior for sessions: keep them around for another
518      * minute after the are no longer needed. Must be called by the
519      * creator of the session right before it would normally cause the
520      * destruction of the session.
521      *
522      * This allows another client to attach and/or get information
523      * about the session.
524      *
525      * This is implemented as a timeout which holds a reference to the
526      * session. Once the timeout fires, it is called and then removed,
527      * which removes the reference.
528      */
529     void delaySessionDestruction(const boost::shared_ptr<Session> &session);
530
531     /**
532      * Works for any kind of object: keep shared pointer until the
533      * event loop is idle, then unref it inside. Useful for instances
534      * which need to delete themselves.
535      */
536     template <class T> void delayDeletion(const boost::shared_ptr<T> &t) {
537         // The functor will never be called, important here is only
538         // that it contains a copy of the shared pointer.
539         m_delayDeletion.push_back(boost::bind(delayDeletionDummy<T>, t));
540         g_idle_add(&Server::delayDeletionCb, this);
541     }
542
543     template <class T> static void delayDeletionDummy(const boost::shared_ptr<T> &t) throw () {}
544     static gboolean delayDeletionCb(gpointer userData) throw () {
545         Server *me = static_cast<Server *>(userData);
546
547         try {
548             me->m_delayDeletion.clear();
549         } catch (...) {
550             // Something unexpected went wrong, can only shut down.
551             Exception::handle(HANDLE_EXCEPTION_FATAL);
552         }
553         return false;
554     }
555
556     /**
557      * Handle the password request from a specific session. Ask our
558      * clients, relay answer to session if it is still around at the
559      * time when we get the response.
560      *
561      * Server does not keep a strong reference to info request,
562      * caller must do that or the request will automatically be
563      * deleted.
564      */
565     boost::shared_ptr<InfoReq> passwordRequest(const std::string &descr,
566                                                const ConfigPasswordKey &key,
567                                                const boost::weak_ptr<Session> &session);
568
569     /** got response for earlier request, need to extract password and tell session */
570     void passwordResponse(const StringMap &response,
571                           const boost::weak_ptr<Session> &session);
572
573     /**
574      * Invokes the given callback once in the given amount of seconds.
575      * Keeps a copy of the callback. If the Server is destructed
576      * before that time, then the callback will be deleted without
577      * being called.
578      */
579     void addTimeout(const boost::function<void ()> &callback,
580                     int seconds);
581
582     /**
583      * InfoReq will be added to map automatically and removed again
584      * when it completes or times out. Caller is responsible for
585      * calling removeInfoReq() when the request becomes obsolete
586      * sooner than that.
587      */
588     boost::shared_ptr<InfoReq> createInfoReq(const string &type,
589                                              const std::map<string, string> &parameters,
590                                              const Session &session);
591     void autoTermRef(int counts = 1) { m_autoTerm.ref(counts); }
592
593     void autoTermUnref(int counts = 1) { m_autoTerm.unref(counts); }
594
595     /** callback to reset for auto termination checking */
596     void autoTermCallback() { m_autoTerm.reset(); }
597
598     /** poll_nm callback for connman, used for presence detection*/
599     void connmanCallback(const std::map <std::string, boost::variant <std::vector <std::string> > >& props, const string &error);
600
601     PresenceStatus& getPresenceStatus();
602
603     void clearPeerTempls() { m_matchedTempls.clear(); }
604     void addPeerTempl(const string &templName, const boost::shared_ptr<SyncConfig::TemplateDescription> peerTempl);
605
606     boost::shared_ptr<SyncConfig::TemplateDescription> getPeerTempl(const string &peer);
607
608     /**
609      * methods to operate device list. See DeviceList definition.
610      * The device id here is the identifier of device, the same as  definition in DeviceList.
611      * In bluetooth devices, it refers to actually the mac address of the bluetooth.
612      * The finger print and match mode is used to match templates.
613      */
614     /** get sync devices */
615     void getDeviceList(SyncConfig::DeviceList &devices);
616     /** get a device according to device id. If not found, return false. */
617     bool getDevice(const string &deviceId, SyncConfig::DeviceDescription &device);
618     /** add a device */
619     void addDevice(const SyncConfig::DeviceDescription &device);
620     /** remove a device by device id. If not found, do nothing */
621     void removeDevice(const string &deviceId);
622     /** update a device with the given device information. If not found, do nothing */
623     void updateDevice(const string &deviceId, const SyncConfig::DeviceDescription &device);
624
625     /** emit a presence signal */
626     void emitPresence(const string &server, const string &status, const string &transport)
627     {
628         presence(server, status, transport);
629     }
630
631     /**
632      * Returns new unique session ID. Implemented with a running
633      * counter. Checks for overflow, but not currently for active
634      * sessions.
635      */
636     std::string getNextSession();
637
638     /**
639      * Number of seconds to wait after file modifications are observed
640      * before shutting down or restarting. Shutting down could be done
641      * immediately, but restarting might not work right away. 10
642      * seconds was chosen because every single package is expected to
643      * be upgraded on disk in that interval. If a long-running system
644      * upgrade replaces additional packages later, then the server
645      * might restart multiple times during a system upgrade. Because it
646      * never runs operations directly after starting, that shouldn't
647      * be a problem.
648      */
649     static const int SHUTDOWN_QUIESENCE_SECONDS = 10;
650
651     /**
652      * false if any client requested suppression of notifications
653      */
654     bool notificationsEnabled();
655
656     /**
657      * implement virtual method from LogStdout.
658      * Not only print the message in the console
659      * but also send them as signals to clients
660      */
661     virtual void messagev(Level level,
662                           const char *prefix,
663                           const char *file,
664                           int line,
665                           const char *function,
666                           const char *format,
667                           va_list args) {
668         messagev(level, prefix, file, line,
669                  function, format, args,
670                  getPath(),
671                  getProcessName());
672     }
673     void messagev(Level level,
674                   const char *prefix,
675                   const char *file,
676                   int line,
677                   const char *function,
678                   const char *format,
679                   va_list args,
680                   const std::string &dbusPath,
681                   const std::string &procname);
682
683     virtual bool isProcessSafe() const { return false; }
684 };
685
686 // extensions to the D-Bus server, created dynamically by main()
687 #ifdef ENABLE_DBUS_PIM
688 boost::shared_ptr<GDBusCXX::DBusObjectHelper> CreateContactManager(const boost::shared_ptr<Server> &server, bool start);
689 #endif
690
691 SE_END_CXX
692
693 #endif // SYNCEVO_DBUS_SERVER_H