blob: ecb6cfc0e10f288b3e9acedac240c8f0500e9c64 [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));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800290
291 if (!new_dbus)
292 return NULL;
293
David Sodman8ef20062015-01-06 09:23:40 -0800294 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700295
296 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
297 if (dbus_error_is_set(&err)) {
298 LOG(ERROR, "Cannot get dbus connection");
299 free(new_dbus);
300 return NULL;
301 }
302
David Sodman8ef20062015-01-06 09:23:40 -0800303 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
304 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
305
306 if (result <= 0) {
307 LOG(ERROR, "Unable to get name for server");
308 }
309
310 stat = dbus_connection_register_object_path(new_dbus->conn,
311 kFreconDbusPath,
312 &frecon_vtable,
313 NULL);
314
315 if (!stat) {
316 LOG(ERROR, "failed to register object path");
317 }
318
319 stat = dbus_connection_set_watch_functions(new_dbus->conn,
320 add_watch, remove_watch, toggle_watch,
321 new_dbus, NULL);
322
323 if (!stat) {
324 LOG(ERROR, "Failed to set watch functions");
325 }
326
David Sodmanbbcb0522014-09-19 10:34:07 -0700327 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
328
329 return new_dbus;
330}
331
David Sodman003faed2014-11-03 09:02:10 -0800332bool dbus_method_call0(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800333 const char* service_path, const char* service_interface,
334 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800335{
336 DBusMessage *msg = NULL;
337
338 msg = dbus_message_new_method_call(service_name,
339 service_path, service_interface, method);
340
341 if (!msg)
342 return false;
343
344 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800345 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800346 dbus_message_unref(msg);
347 return false;
348 }
349
350 dbus_connection_flush(dbus->conn);
351 dbus_message_unref(msg);
352
353 return true;
354}
355
356bool dbus_method_call1(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800357 const char* service_path, const char* service_interface,
358 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700359{
360 DBusMessage *msg = NULL;
361
362 msg = dbus_message_new_method_call(service_name,
363 service_path, service_interface, method);
364
365 if (!msg)
366 return false;
367
368 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700369 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700370 dbus_message_unref(msg);
371 return false;
372 }
373
374 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800375 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700376 dbus_message_unref(msg);
377 return false;
378 }
379
380 dbus_connection_flush(dbus->conn);
381 dbus_message_unref(msg);
382
383 return true;
384}
385
386static void
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800387dbus_path_unregister_function(DBusConnection* connection, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700388{
389}
390
391static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800392dbus_message_function(DBusConnection* connection,
393 DBusMessage* message, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700394{
395 dbus_t* dbus = (dbus_t*)user_data;
396
397 if (dbus_message_is_signal(message, dbus->signal.interface,
398 dbus->signal.signal)) {
399 dbus->signal.signal_handler(dbus, dbus->signal.user_data);
400 }
401 return DBUS_HANDLER_RESULT_HANDLED;
402}
403
404bool dbus_signal_match_handler(
405 dbus_t* dbus,
406 const char* signal,
407 const char* path,
408 const char* interface,
409 const char* rule,
410 dbus_message_handler_t handler,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800411 void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700412{
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800413 DBusError err;
David Sodmanbbcb0522014-09-19 10:34:07 -0700414 dbus->signal.vtable.unregister_function = dbus_path_unregister_function;
415 dbus->signal.vtable.message_function = dbus_message_function;
416 dbus->signal.signal_handler = handler;
417 dbus->signal.signal = signal;
418 dbus->signal.user_data = user_data;
419 dbus->signal.interface = interface;
420
421 if (!dbus_connection_register_object_path(dbus->conn, path,
422 &dbus->signal.vtable, dbus)) {
423 LOG(ERROR, "register_object_path failed");
424 return false;
425 }
426
427 dbus_error_init(&err);
428 dbus_bus_add_match(dbus->conn, rule, &err);
429 if (dbus_error_is_set(&err)) {
430 LOG(ERROR, "add_match failed: %s", err.message);
431 return false;
432 }
433
434 return true;
435}
436
David Sodmanbbcb0522014-09-19 10:34:07 -0700437void dbus_destroy(dbus_t* dbus)
438{
439 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800440 * dbus_bus_get() is, unref documentation is rather
441 * unclear. Not a big issue but it would be nice to
442 * clean up properly here
443 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700444 /* dbus_connection_unref(dbus->conn); */
David Sodman8ef20062015-01-06 09:23:40 -0800445 if (dbus)
446 free(dbus);
447}
448
449void dbus_add_fd(dbus_t* dbus, fd_set* read_set, fd_set* exception_set)
450{
451 if (dbus->fd < 0)
452 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
453
454 if (dbus->fd >= 0) {
455 FD_SET(dbus->fd, read_set);
456 FD_SET(dbus->fd, exception_set);
457 }
458}
459
460int dbus_get_fd(dbus_t* dbus)
461{
462 if (dbus->fd < 0)
463 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
464
465 return dbus->fd;
466}
467
David Sodman8ef20062015-01-06 09:23:40 -0800468void dbus_dispatch_io(dbus_t* dbus)
469{
470 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
471 while (dbus_connection_get_dispatch_status(dbus->conn)
472 == DBUS_DISPATCH_DATA_REMAINS) {
473 dbus_connection_dispatch(dbus->conn);
474 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700475}