blob: 688a301726ce583dacceac2e049dcfc0e240baf4 [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>
8#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -08009
10#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 {
24 DBusConnection *conn;
25 int terminate;
David Sodman8ef20062015-01-06 09:23:40 -080026 DBusWatch *watch;
27 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
39_handle_switchvt(DBusConnection *connection, DBusMessage *message)
40{
41 DBusMessage *reply;
42 DBusMessage *msg;
43 DBusError error;
44 dbus_bool_t stat;
45 terminal_t *terminal;
46 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
108_handle_makevt(DBusConnection *connection, DBusMessage *message)
109{
110 DBusMessage *reply;
111 DBusError error;
112 dbus_bool_t stat;
113 terminal_t *terminal;
114 unsigned int vt;
115 const char *reply_str;
116
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
144_handle_terminate(DBusConnection *connection, DBusMessage *message)
145{
146 DBusMessage *reply;
147
148 reply = dbus_message_new_method_return(message);
149 dbus_connection_send(connection, reply, NULL);
150 exit(EXIT_SUCCESS);
151}
152
153
154#define NUM_IMAGE_PARAMETERS (2)
155static DBusHandlerResult
156_handle_image(DBusConnection *connection, DBusMessage *message)
157{
158 DBusMessage *reply;
159 DBusError error;
160 dbus_bool_t stat;
161 terminal_t *terminal;
162 image_t *image;
163 int i;
164 int x, y;
165 char* option[NUM_IMAGE_PARAMETERS];
166 char* optname;
167 char* optval;
168 int status;
169
170 dbus_error_init(&error);
171 stat = dbus_message_get_args(message, &error,
172 DBUS_TYPE_STRING, &option[0],
173 DBUS_TYPE_STRING, &option[1],
174 DBUS_TYPE_INVALID);
175
176 image = image_create();
177 if (image == NULL) {
178 LOG(WARNING, "failed to create image");
179 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180 }
181
182 if (stat) {
183 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
184 optname = NULL;
185 optval = NULL;
186 parse_image_option(option[i], &optname, &optval);
187 if (strncmp(optname, "image", strlen("image")) == 0) {
188 image_set_filename(image, optval);
189 } else if (strncmp(optname, "location", strlen("location")) == 0) {
190 parse_location(optval, &x, &y);
191 image_set_location(image, x, y);
192 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
193 parse_location(optval, &x, &y);
194 image_set_offset(image, x, y);
195 }
196 if (optname)
197 free(optname);
198 if (optval)
199 free(optval);
200 }
201 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700202 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800203 }
204
205 status = image_load_image_from_file(image);
206 if (status != 0) {
207 LOG(WARNING, "image_load_image_from_file failed: %d", status);
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800209 }
210
211 terminal = input_create_term(0);
212 if (!terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700213 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800214
David Sodmanf0a925a2015-05-04 11:19:19 -0700215 status = term_show_image(terminal, image);
216 if (status != 0) {
217 LOG(WARNING, "term_show_image failed: %d", status);
218 goto fail;
219 }
David Sodman8ef20062015-01-06 09:23:40 -0800220 image_release(image);
221
222 reply = dbus_message_new_method_return(message);
223 dbus_connection_send(connection, reply, NULL);
224
225 return DBUS_HANDLER_RESULT_HANDLED;
David Sodmanf0a925a2015-05-04 11:19:19 -0700226fail:
227 if (image)
228 image_release(image);
229 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800230}
231
232static void
233_frecon_dbus_unregister(DBusConnection *connection, void* user_data)
234{
235}
236
237
238static DBusHandlerResult
239_frecon_dbus_message_handler(DBusConnection *connection, DBusMessage *message, void* user_data)
240{
241 if (dbus_message_is_method_call(message,
242 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
243 return _handle_switchvt(connection, message);
244 } else if (dbus_message_is_method_call(message,
245 kFreconDbusInterface, COMMAND_MAKE_VT)) {
246 return _handle_makevt(connection, message);
247 }
248 else if (dbus_message_is_method_call(message,
249 kFreconDbusInterface, COMMAND_TERMINATE)) {
250 return _handle_terminate(connection, message);
251 } else if (dbus_message_is_method_call(message,
252 kFreconDbusInterface, COMMAND_IMAGE)) {
253 return _handle_image(connection, message);
254 }
255
256 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
257
258}
259
260static DBusObjectPathVTable
261frecon_vtable = {
262 _frecon_dbus_unregister,
263 _frecon_dbus_message_handler,
264 NULL
265};
266
267dbus_bool_t add_watch(DBusWatch *w, void* data)
268{
269 dbus_t *dbus = (dbus_t*)data;
270 dbus->watch = w;
271
272 return TRUE;
273}
274
275void remove_watch(DBusWatch *w, void* data)
276{
277}
278
279void toggle_watch(DBusWatch *w, void* data)
280{
281}
282
David Sodmanbbcb0522014-09-19 10:34:07 -0700283dbus_t* dbus_init()
284{
285 dbus_t* new_dbus;
286 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800287 int result;
288 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700289
290 dbus_error_init(&err);
291
292 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
David Sodman8ef20062015-01-06 09:23:40 -0800293 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700294
295 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
296 if (dbus_error_is_set(&err)) {
297 LOG(ERROR, "Cannot get dbus connection");
298 free(new_dbus);
299 return NULL;
300 }
301
David Sodman8ef20062015-01-06 09:23:40 -0800302 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
303 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
304
305 if (result <= 0) {
306 LOG(ERROR, "Unable to get name for server");
307 }
308
309 stat = dbus_connection_register_object_path(new_dbus->conn,
310 kFreconDbusPath,
311 &frecon_vtable,
312 NULL);
313
314 if (!stat) {
315 LOG(ERROR, "failed to register object path");
316 }
317
318 stat = dbus_connection_set_watch_functions(new_dbus->conn,
319 add_watch, remove_watch, toggle_watch,
320 new_dbus, NULL);
321
322 if (!stat) {
323 LOG(ERROR, "Failed to set watch functions");
324 }
325
David Sodmanbbcb0522014-09-19 10:34:07 -0700326 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
327
328 return new_dbus;
329}
330
331
David Sodman003faed2014-11-03 09:02:10 -0800332bool dbus_method_call0(dbus_t* dbus, const char* service_name,
333 const char* service_path, const char* service_interface,
334 const char* method)
335{
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,
David Sodmanbbcb0522014-09-19 10:34:07 -0700357 const char* service_path, const char* service_interface,
David Sodman19e4f9d2015-03-10 11:11:09 -0700358 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
387dbus_path_unregister_function(DBusConnection *connection, void *user_data)
388{
389}
390
391static DBusHandlerResult
392dbus_message_function(DBusConnection *connection,
393 DBusMessage *message, void* user_data)
394{
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,
411 void *user_data)
412{
413 DBusError err;
414 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
440 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 /* dbus_connection_unref(dbus->conn); */
David Sodman8ef20062015-01-06 09:23:40 -0800444 if (dbus)
445 free(dbus);
446}
447
448void dbus_add_fd(dbus_t* dbus, fd_set* read_set, fd_set* exception_set)
449{
450 if (dbus->fd < 0)
451 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
452
453 if (dbus->fd >= 0) {
454 FD_SET(dbus->fd, read_set);
455 FD_SET(dbus->fd, exception_set);
456 }
457}
458
459int dbus_get_fd(dbus_t* dbus)
460{
461 if (dbus->fd < 0)
462 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
463
464 return dbus->fd;
465}
466
467
468void 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}