File: KmDbusTestServer.cpp

package info (click to toggle)
keyman 18.0.246-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,316 kB
  • sloc: python: 52,784; cpp: 21,289; sh: 7,633; ansic: 4,823; xml: 3,617; perl: 959; makefile: 139; javascript: 138
file content (159 lines) | stat: -rw-r--r-- 3,841 bytes parent folder | download | duplicates (2)
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
// DBus test server. The server will start and listen on a non-standard DBus.
// It runs until the DBus Exit method gets called.
#include "config.h"
#include <fstream>
#include <gio/gio.h>
#include <iostream>
#if DBUS_IMPLEMENTATION == SYSTEMD
#include <systemd/sd-bus.h>
#else
#include <basu/sd-bus.h>
#endif

#include "KmDbusTestServer.h"

#ifndef KEYMAN_TEST_SERVICE_PATH
#warning KEYMAN_TEST_SERVICE_PATH is undefined
#define KEYMAN_TEST_SERVICE_PATH "."
#endif

using namespace std;

class KmDbusTestServer
{
public:
  GTestDBus *dbus;
  sd_bus *bus       = NULL;
  gboolean exitFlag = FALSE;

public:
  KmDbusTestServer();
  ~KmDbusTestServer();

  void Loop();
};

static int32_t
on_exit_method(sd_bus_message *msg, void *user_data, sd_bus_error *ret_error) {
  g_debug("%s called", __FUNCTION__);
  KmDbusTestServer* server = (KmDbusTestServer*)user_data;

  *ret_error = SD_BUS_ERROR_NULL;

  server->exitFlag = TRUE;

  return sd_bus_reply_method_return(msg, "");
}

static const sd_bus_vtable test_service_vtable[] = {
  SD_BUS_VTABLE_START(0),
    SD_BUS_METHOD("Exit", "", "", on_exit_method, 0),
  SD_BUS_VTABLE_END
};

KmDbusTestServer::KmDbusTestServer()
{
  dbus  = g_test_dbus_new(G_TEST_DBUS_NONE);

  // Add the private directory with our in-tree service files.
  g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH);

  std::cout << "Add service dir to " << KEYMAN_TEST_SERVICE_PATH << std::endl;

  // Start the private D-Bus daemon
  g_test_dbus_up(dbus);

  const gchar *address = g_test_dbus_get_bus_address(dbus);

  std::cout << "Test server running on: " << address << std::endl;

  ofstream file("/tmp/km-test-server.env", ios_base::out);
  if (file) {
    // write the address to a file which can be sourced
    file << "export DBUS_SESSION_BUS_ADDRESS=" << address << std::endl;
    file.close();
  }
}

KmDbusTestServer::~KmDbusTestServer()
{
  if (bus) {
    sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME);
    sd_bus_close(bus);
    sd_bus_unref(bus);
  }

  g_test_dbus_down(dbus);
  g_object_unref(dbus);
}

void KmDbusTestServer::Loop()
{
  int ret;

  ret = sd_bus_open_user(&bus);

  if (ret < 0) {
    g_error("Failed to connect to system bus: %s", strerror(-ret));
    return;
  }

  guint exitFlag = FALSE;

  // Install the object
  ret = sd_bus_add_object_vtable(bus, NULL, KEYMAN_TESTSVC_OBJECT_PATH,
    KEYMAN_TESTSVC_INTERFACE_NAME, test_service_vtable, &exitFlag);
  if (ret < 0) {
    g_error("Failed to issue method call: %s", strerror(-ret));
    return;
  }

  // Take a well-known service name so that clients can find us
  ret = sd_bus_request_name(bus, KEYMAN_TESTSVC_BUS_NAME, 0);
  if (ret < 0) {
    g_error("Failed to acquire service name: %s", strerror(-ret));
    return;
  }

  for (;;) {
    // Process requests
    ret = sd_bus_process(bus, NULL);
    g_debug("sd_bus_process returned %d, exitFlag=%d", ret, exitFlag);
    if (ret < 0) {
      g_error("Failed to process bus: %s", strerror(-ret));
      return;
    }
    if (exitFlag) {
      // `exitFlag` can be modified by the callback function
      // `on_exit_method` which can be called by `sd_bus_process`
      g_debug("Exiting loop");
      return;
    }

    if (ret > 0) {
      // we processed a request, try to process another one, right-away
      continue;
    }

    // Wait for the next request to process
    ret = sd_bus_wait(bus, (uint64_t)-1);
    g_debug("sd_bus_wait returned %d", ret);
    if (ret < 0) {
      g_error("Failed to wait on bus: %s", strerror(-ret));
      return;
    }
  }
}

int
main(int argc, char *argv[]) {
  if (!g_file_test(KEYMAN_TEST_SERVICE_PATH, G_FILE_TEST_IS_DIR)) {
    std::cerr << "ERROR: Directory " << KEYMAN_TEST_SERVICE_PATH << " doesn't exist! Exiting." << std::endl;
    return 1;
  }

  KmDbusTestServer testServer;
  testServer.Loop();

  return 0;
}