blob: 26ae95f44d711b305d636edf44327b72d88ca449 [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <stdlib.h>
David Sodman8ef20062015-01-06 09:23:40 -08008
Stéphane Marchesin62561a12015-12-11 17:32:37 -08009#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -080010#include "dbus_interface.h"
11#include "image.h"
12#include "input.h"
13#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070014#include "util.h"
15
David Sodman8ef20062015-01-06 09:23:40 -080016#define COMMAND_MAKE_VT "MakeVT"
17#define COMMAND_SWITCH_VT "SwitchVT"
18#define COMMAND_TERMINATE "Terminate"
19#define COMMAND_IMAGE "Image"
20
21#define DBUS_DEFAULT_DELAY 3000
22
David Sodmanbbcb0522014-09-19 10:34:07 -070023struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080024 DBusConnection* conn;
David Sodmanbbcb0522014-09-19 10:34:07 -070025 int terminate;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080027 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070028 struct {
29 DBusObjectPathVTable vtable;
30 const char* interface;
31 const char* signal;
32 const char* rule;
33 void* user_data;
34 dbus_message_handler_t signal_handler;
35 } signal;
36};
37
David Sodman8ef20062015-01-06 09:23:40 -080038static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080039handle_switchvt(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -080040{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080041 DBusMessage* reply;
42 DBusMessage* msg;
David Sodman8ef20062015-01-06 09:23:40 -080043 DBusError error;
44 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080045 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -080046 unsigned int vt;
47
48 dbus_error_init(&error);
49 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
50 &vt, DBUS_TYPE_INVALID);
51
52 if (!stat) {
53 LOG(ERROR, "SwitchVT method error, no VT argument");
54 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
55 }
56
57 if (vt > input_get_maxterminals()) {
58 LOG(ERROR, "SwtichVT: invalid terminal");
59 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
60 }
61
62 if (vt == 0) {
63 terminal = input_create_term(vt);
64 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -070065 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080066 msg = dbus_message_new_method_call(
67 kLibCrosServiceName,
68 kLibCrosServicePath,
69 kLibCrosServiceInterface,
70 kTakeDisplayOwnership);
71 dbus_connection_send_with_reply_and_block(connection, msg,
72 DBUS_DEFAULT_DELAY, NULL);
73 }
74 reply = dbus_message_new_method_return(message);
75 dbus_connection_send(connection, reply, NULL);
76 return DBUS_HANDLER_RESULT_HANDLED;
77 } else {
78 /*
79 * If we are switching to a new term, and if a
80 * given term is active, then de-activate the
81 * current terminal
82 */
83 terminal = input_create_term(0);
84 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -070085 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080086
87 terminal = input_create_term(vt);
88 if (term_is_valid(terminal)) {
89 msg = dbus_message_new_method_call(
90 kLibCrosServiceName,
91 kLibCrosServicePath,
92 kLibCrosServiceInterface,
93 kReleaseDisplayOwnership);
94 dbus_connection_send_with_reply_and_block(connection, msg,
95 DBUS_DEFAULT_DELAY, NULL);
96 term_activate(terminal);
97
98 reply = dbus_message_new_method_return(message);
99 dbus_connection_send(connection, reply, NULL);
100 return DBUS_HANDLER_RESULT_HANDLED;
101 }
102 }
103
104 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
105}
106
107static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800108handle_makevt(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800109{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800110 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800111 DBusError error;
112 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800113 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -0800114 unsigned int vt;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800115 const char* reply_str;
David Sodman8ef20062015-01-06 09:23:40 -0800116
117 dbus_error_init(&error);
118 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
119 &vt, DBUS_TYPE_INVALID);
120
121 if (!stat) {
122 LOG(ERROR, "SwitchVT method error, not VT argument");
123 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
124 }
125
126 if ((vt < 1) || (vt > input_get_maxterminals())) {
127 LOG(ERROR, "SwtichVT: invalid terminal");
128 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
129 }
130
131 terminal = input_create_term(vt);
132 reply_str = term_get_ptsname(terminal);
133
134 reply = dbus_message_new_method_return(message);
135 dbus_message_append_args(reply,
136 DBUS_TYPE_STRING, &reply_str,
137 DBUS_TYPE_INVALID);
138 dbus_connection_send(connection, reply, NULL);
139
140 return DBUS_HANDLER_RESULT_HANDLED;
141}
142
143static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800144handle_terminate(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800145{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800146 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800147
148 reply = dbus_message_new_method_return(message);
149 dbus_connection_send(connection, reply, NULL);
150 exit(EXIT_SUCCESS);
151}
152
David Sodman8ef20062015-01-06 09:23:40 -0800153#define NUM_IMAGE_PARAMETERS (2)
154static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800155handle_image(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800156{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800157 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800158 DBusError error;
159 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800160 terminal_t* terminal;
161 image_t* image;
David Sodman8ef20062015-01-06 09:23:40 -0800162 int i;
163 int x, y;
164 char* option[NUM_IMAGE_PARAMETERS];
165 char* optname;
166 char* optval;
167 int status;
168
169 dbus_error_init(&error);
170 stat = dbus_message_get_args(message, &error,
171 DBUS_TYPE_STRING, &option[0],
172 DBUS_TYPE_STRING, &option[1],
173 DBUS_TYPE_INVALID);
174
175 image = image_create();
176 if (image == NULL) {
177 LOG(WARNING, "failed to create image");
178 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
179 }
180
181 if (stat) {
182 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
183 optname = NULL;
184 optval = NULL;
185 parse_image_option(option[i], &optname, &optval);
186 if (strncmp(optname, "image", strlen("image")) == 0) {
187 image_set_filename(image, optval);
188 } else if (strncmp(optname, "location", strlen("location")) == 0) {
189 parse_location(optval, &x, &y);
190 image_set_location(image, x, y);
191 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
192 parse_location(optval, &x, &y);
193 image_set_offset(image, x, y);
194 }
195 if (optname)
196 free(optname);
197 if (optval)
198 free(optval);
199 }
200 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700201 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800202 }
203
204 status = image_load_image_from_file(image);
205 if (status != 0) {
206 LOG(WARNING, "image_load_image_from_file failed: %d", status);
David Sodmanf0a925a2015-05-04 11:19:19 -0700207 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800208 }
209
210 terminal = input_create_term(0);
211 if (!terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700212 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800213
David Sodmanf0a925a2015-05-04 11:19:19 -0700214 status = term_show_image(terminal, image);
215 if (status != 0) {
216 LOG(WARNING, "term_show_image failed: %d", status);
217 goto fail;
218 }
David Sodman8ef20062015-01-06 09:23:40 -0800219 image_release(image);
220
221 reply = dbus_message_new_method_return(message);
222 dbus_connection_send(connection, reply, NULL);
223
224 return DBUS_HANDLER_RESULT_HANDLED;
David Sodmanf0a925a2015-05-04 11:19:19 -0700225fail:
226 if (image)
227 image_release(image);
228 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800229}
230
231static void
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800232frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800233{
234}
235
David Sodman8ef20062015-01-06 09:23:40 -0800236static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800237frecon_dbus_message_handler(DBusConnection* connection, DBusMessage* message, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800238{
239 if (dbus_message_is_method_call(message,
240 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800241 return handle_switchvt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800242 } else if (dbus_message_is_method_call(message,
243 kFreconDbusInterface, COMMAND_MAKE_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800244 return handle_makevt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800245 }
246 else if (dbus_message_is_method_call(message,
247 kFreconDbusInterface, COMMAND_TERMINATE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800248 return handle_terminate(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800249 } else if (dbus_message_is_method_call(message,
250 kFreconDbusInterface, COMMAND_IMAGE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800251 return handle_image(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800252 }
253
254 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800255}
256
257static DBusObjectPathVTable
258frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800259 frecon_dbus_unregister,
260 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -0800261 NULL
262};
263
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800264static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800265{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800266 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -0800267 dbus->watch = w;
268
269 return TRUE;
270}
271
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800272static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800273{
274}
275
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800276static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800277{
278}
279
David Sodmanbbcb0522014-09-19 10:34:07 -0700280dbus_t* dbus_init()
281{
282 dbus_t* new_dbus;
283 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800284 int result;
285 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700286
287 dbus_error_init(&err);
288
289 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
David Sodman8ef20062015-01-06 09:23:40 -0800290 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700291
292 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
293 if (dbus_error_is_set(&err)) {
294 LOG(ERROR, "Cannot get dbus connection");
295 free(new_dbus);
296 return NULL;
297 }
298
David Sodman8ef20062015-01-06 09:23:40 -0800299 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
300 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
301
302 if (result <= 0) {
303 LOG(ERROR, "Unable to get name for server");
304 }
305
306 stat = dbus_connection_register_object_path(new_dbus->conn,
307 kFreconDbusPath,
308 &frecon_vtable,
309 NULL);
310
311 if (!stat) {
312 LOG(ERROR, "failed to register object path");
313 }
314
315 stat = dbus_connection_set_watch_functions(new_dbus->conn,
316 add_watch, remove_watch, toggle_watch,
317 new_dbus, NULL);
318
319 if (!stat) {
320 LOG(ERROR, "Failed to set watch functions");
321 }
322
David Sodmanbbcb0522014-09-19 10:34:07 -0700323 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
324
325 return new_dbus;
326}
327
David Sodman003faed2014-11-03 09:02:10 -0800328bool dbus_method_call0(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800329 const char* service_path, const char* service_interface,
330 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800331{
332 DBusMessage *msg = NULL;
333
334 msg = dbus_message_new_method_call(service_name,
335 service_path, service_interface, method);
336
337 if (!msg)
338 return false;
339
340 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800341 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800342 dbus_message_unref(msg);
343 return false;
344 }
345
346 dbus_connection_flush(dbus->conn);
347 dbus_message_unref(msg);
348
349 return true;
350}
351
352bool dbus_method_call1(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800353 const char* service_path, const char* service_interface,
354 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700355{
356 DBusMessage *msg = NULL;
357
358 msg = dbus_message_new_method_call(service_name,
359 service_path, service_interface, method);
360
361 if (!msg)
362 return false;
363
364 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700365 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700366 dbus_message_unref(msg);
367 return false;
368 }
369
370 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800371 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700372 dbus_message_unref(msg);
373 return false;
374 }
375
376 dbus_connection_flush(dbus->conn);
377 dbus_message_unref(msg);
378
379 return true;
380}
381
382static void
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800383dbus_path_unregister_function(DBusConnection* connection, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700384{
385}
386
387static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800388dbus_message_function(DBusConnection* connection,
389 DBusMessage* message, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700390{
391 dbus_t* dbus = (dbus_t*)user_data;
392
393 if (dbus_message_is_signal(message, dbus->signal.interface,
394 dbus->signal.signal)) {
395 dbus->signal.signal_handler(dbus, dbus->signal.user_data);
396 }
397 return DBUS_HANDLER_RESULT_HANDLED;
398}
399
400bool dbus_signal_match_handler(
401 dbus_t* dbus,
402 const char* signal,
403 const char* path,
404 const char* interface,
405 const char* rule,
406 dbus_message_handler_t handler,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800407 void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700408{
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800409 DBusError err;
David Sodmanbbcb0522014-09-19 10:34:07 -0700410 dbus->signal.vtable.unregister_function = dbus_path_unregister_function;
411 dbus->signal.vtable.message_function = dbus_message_function;
412 dbus->signal.signal_handler = handler;
413 dbus->signal.signal = signal;
414 dbus->signal.user_data = user_data;
415 dbus->signal.interface = interface;
416
417 if (!dbus_connection_register_object_path(dbus->conn, path,
418 &dbus->signal.vtable, dbus)) {
419 LOG(ERROR, "register_object_path failed");
420 return false;
421 }
422
423 dbus_error_init(&err);
424 dbus_bus_add_match(dbus->conn, rule, &err);
425 if (dbus_error_is_set(&err)) {
426 LOG(ERROR, "add_match failed: %s", err.message);
427 return false;
428 }
429
430 return true;
431}
432
David Sodmanbbcb0522014-09-19 10:34:07 -0700433void dbus_destroy(dbus_t* dbus)
434{
435 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800436 * dbus_bus_get() is, unref documentation is rather
437 * unclear. Not a big issue but it would be nice to
438 * clean up properly here
439 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700440 /* dbus_connection_unref(dbus->conn); */
David Sodman8ef20062015-01-06 09:23:40 -0800441 if (dbus)
442 free(dbus);
443}
444
445void dbus_add_fd(dbus_t* dbus, fd_set* read_set, fd_set* exception_set)
446{
447 if (dbus->fd < 0)
448 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
449
450 if (dbus->fd >= 0) {
451 FD_SET(dbus->fd, read_set);
452 FD_SET(dbus->fd, exception_set);
453 }
454}
455
456int dbus_get_fd(dbus_t* dbus)
457{
458 if (dbus->fd < 0)
459 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
460
461 return dbus->fd;
462}
463
David Sodman8ef20062015-01-06 09:23:40 -0800464void dbus_dispatch_io(dbus_t* dbus)
465{
466 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
467 while (dbus_connection_get_dispatch_status(dbus->conn)
468 == DBUS_DISPATCH_DATA_REMAINS) {
469 dbus_connection_dispatch(dbus->conn);
470 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700471}