blob: 47fa8a7f457dbfc3e372853a7ca4aeba805ea5b8 [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)) {
65 input_ungrab();
66 terminal->active = false;
67 video_release(terminal->video);
68 msg = dbus_message_new_method_call(
69 kLibCrosServiceName,
70 kLibCrosServicePath,
71 kLibCrosServiceInterface,
72 kTakeDisplayOwnership);
73 dbus_connection_send_with_reply_and_block(connection, msg,
74 DBUS_DEFAULT_DELAY, NULL);
75 }
76 reply = dbus_message_new_method_return(message);
77 dbus_connection_send(connection, reply, NULL);
78 return DBUS_HANDLER_RESULT_HANDLED;
79 } else {
80 /*
81 * If we are switching to a new term, and if a
82 * given term is active, then de-activate the
83 * current terminal
84 */
85 terminal = input_create_term(0);
86 if (term_is_active(terminal))
87 terminal->active = false;
88
89 terminal = input_create_term(vt);
90 if (term_is_valid(terminal)) {
91 msg = dbus_message_new_method_call(
92 kLibCrosServiceName,
93 kLibCrosServicePath,
94 kLibCrosServiceInterface,
95 kReleaseDisplayOwnership);
96 dbus_connection_send_with_reply_and_block(connection, msg,
97 DBUS_DEFAULT_DELAY, NULL);
98 term_activate(terminal);
99
100 reply = dbus_message_new_method_return(message);
101 dbus_connection_send(connection, reply, NULL);
102 return DBUS_HANDLER_RESULT_HANDLED;
103 }
104 }
105
106 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
107}
108
109static DBusHandlerResult
110_handle_makevt(DBusConnection *connection, DBusMessage *message)
111{
112 DBusMessage *reply;
113 DBusError error;
114 dbus_bool_t stat;
115 terminal_t *terminal;
116 unsigned int vt;
117 const char *reply_str;
118
119 dbus_error_init(&error);
120 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
121 &vt, DBUS_TYPE_INVALID);
122
123 if (!stat) {
124 LOG(ERROR, "SwitchVT method error, not VT argument");
125 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
126 }
127
128 if ((vt < 1) || (vt > input_get_maxterminals())) {
129 LOG(ERROR, "SwtichVT: invalid terminal");
130 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
131 }
132
133 terminal = input_create_term(vt);
134 reply_str = term_get_ptsname(terminal);
135
136 reply = dbus_message_new_method_return(message);
137 dbus_message_append_args(reply,
138 DBUS_TYPE_STRING, &reply_str,
139 DBUS_TYPE_INVALID);
140 dbus_connection_send(connection, reply, NULL);
141
142 return DBUS_HANDLER_RESULT_HANDLED;
143}
144
145static DBusHandlerResult
146_handle_terminate(DBusConnection *connection, DBusMessage *message)
147{
148 DBusMessage *reply;
149
150 reply = dbus_message_new_method_return(message);
151 dbus_connection_send(connection, reply, NULL);
152 exit(EXIT_SUCCESS);
153}
154
155
156#define NUM_IMAGE_PARAMETERS (2)
157static DBusHandlerResult
158_handle_image(DBusConnection *connection, DBusMessage *message)
159{
160 DBusMessage *reply;
161 DBusError error;
162 dbus_bool_t stat;
163 terminal_t *terminal;
164 image_t *image;
165 int i;
166 int x, y;
167 char* option[NUM_IMAGE_PARAMETERS];
168 char* optname;
169 char* optval;
170 int status;
171
172 dbus_error_init(&error);
173 stat = dbus_message_get_args(message, &error,
174 DBUS_TYPE_STRING, &option[0],
175 DBUS_TYPE_STRING, &option[1],
176 DBUS_TYPE_INVALID);
177
178 image = image_create();
179 if (image == NULL) {
180 LOG(WARNING, "failed to create image");
181 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
182 }
183
184 if (stat) {
185 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
186 optname = NULL;
187 optval = NULL;
188 parse_image_option(option[i], &optname, &optval);
189 if (strncmp(optname, "image", strlen("image")) == 0) {
190 image_set_filename(image, optval);
191 } else if (strncmp(optname, "location", strlen("location")) == 0) {
192 parse_location(optval, &x, &y);
193 image_set_location(image, x, y);
194 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
195 parse_location(optval, &x, &y);
196 image_set_offset(image, x, y);
197 }
198 if (optname)
199 free(optname);
200 if (optval)
201 free(optval);
202 }
203 } else {
204 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
205 }
206
207 status = image_load_image_from_file(image);
208 if (status != 0) {
209 LOG(WARNING, "image_load_image_from_file failed: %d", status);
210 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
211 }
212
213 terminal = input_create_term(0);
214 if (!terminal)
215 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
216
217 image_show(image, terminal->video);
218 image_release(image);
219
220 reply = dbus_message_new_method_return(message);
221 dbus_connection_send(connection, reply, NULL);
222
223 return DBUS_HANDLER_RESULT_HANDLED;
224}
225
226static void
227_frecon_dbus_unregister(DBusConnection *connection, void* user_data)
228{
229}
230
231
232static DBusHandlerResult
233_frecon_dbus_message_handler(DBusConnection *connection, DBusMessage *message, void* user_data)
234{
235 if (dbus_message_is_method_call(message,
236 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
237 return _handle_switchvt(connection, message);
238 } else if (dbus_message_is_method_call(message,
239 kFreconDbusInterface, COMMAND_MAKE_VT)) {
240 return _handle_makevt(connection, message);
241 }
242 else if (dbus_message_is_method_call(message,
243 kFreconDbusInterface, COMMAND_TERMINATE)) {
244 return _handle_terminate(connection, message);
245 } else if (dbus_message_is_method_call(message,
246 kFreconDbusInterface, COMMAND_IMAGE)) {
247 return _handle_image(connection, message);
248 }
249
250 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
251
252}
253
254static DBusObjectPathVTable
255frecon_vtable = {
256 _frecon_dbus_unregister,
257 _frecon_dbus_message_handler,
258 NULL
259};
260
261dbus_bool_t add_watch(DBusWatch *w, void* data)
262{
263 dbus_t *dbus = (dbus_t*)data;
264 dbus->watch = w;
265
266 return TRUE;
267}
268
269void remove_watch(DBusWatch *w, void* data)
270{
271}
272
273void toggle_watch(DBusWatch *w, void* data)
274{
275}
276
David Sodmanbbcb0522014-09-19 10:34:07 -0700277dbus_t* dbus_init()
278{
279 dbus_t* new_dbus;
280 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800281 int result;
282 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700283
284 dbus_error_init(&err);
285
286 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
David Sodman8ef20062015-01-06 09:23:40 -0800287 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700288
289 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
290 if (dbus_error_is_set(&err)) {
291 LOG(ERROR, "Cannot get dbus connection");
292 free(new_dbus);
293 return NULL;
294 }
295
David Sodman8ef20062015-01-06 09:23:40 -0800296 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
297 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
298
299 if (result <= 0) {
300 LOG(ERROR, "Unable to get name for server");
301 }
302
303 stat = dbus_connection_register_object_path(new_dbus->conn,
304 kFreconDbusPath,
305 &frecon_vtable,
306 NULL);
307
308 if (!stat) {
309 LOG(ERROR, "failed to register object path");
310 }
311
312 stat = dbus_connection_set_watch_functions(new_dbus->conn,
313 add_watch, remove_watch, toggle_watch,
314 new_dbus, NULL);
315
316 if (!stat) {
317 LOG(ERROR, "Failed to set watch functions");
318 }
319
David Sodmanbbcb0522014-09-19 10:34:07 -0700320 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
321
322 return new_dbus;
323}
324
325
David Sodman003faed2014-11-03 09:02:10 -0800326bool dbus_method_call0(dbus_t* dbus, const char* service_name,
327 const char* service_path, const char* service_interface,
328 const char* method)
329{
330 DBusMessage *msg = NULL;
331
332 msg = dbus_message_new_method_call(service_name,
333 service_path, service_interface, method);
334
335 if (!msg)
336 return false;
337
338 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800339 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800340 dbus_message_unref(msg);
341 return false;
342 }
343
344 dbus_connection_flush(dbus->conn);
345 dbus_message_unref(msg);
346
347 return true;
348}
349
350bool dbus_method_call1(dbus_t* dbus, const char* service_name,
David Sodmanbbcb0522014-09-19 10:34:07 -0700351 const char* service_path, const char* service_interface,
David Sodman19e4f9d2015-03-10 11:11:09 -0700352 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700353{
354 DBusMessage *msg = NULL;
355
356 msg = dbus_message_new_method_call(service_name,
357 service_path, service_interface, method);
358
359 if (!msg)
360 return false;
361
362 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700363 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700364 dbus_message_unref(msg);
365 return false;
366 }
367
368 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800369 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700370 dbus_message_unref(msg);
371 return false;
372 }
373
374 dbus_connection_flush(dbus->conn);
375 dbus_message_unref(msg);
376
377 return true;
378}
379
380static void
381dbus_path_unregister_function(DBusConnection *connection, void *user_data)
382{
383}
384
385static DBusHandlerResult
386dbus_message_function(DBusConnection *connection,
387 DBusMessage *message, void* user_data)
388{
389 dbus_t* dbus = (dbus_t*)user_data;
390
391 if (dbus_message_is_signal(message, dbus->signal.interface,
392 dbus->signal.signal)) {
393 dbus->signal.signal_handler(dbus, dbus->signal.user_data);
394 }
395 return DBUS_HANDLER_RESULT_HANDLED;
396}
397
398bool dbus_signal_match_handler(
399 dbus_t* dbus,
400 const char* signal,
401 const char* path,
402 const char* interface,
403 const char* rule,
404 dbus_message_handler_t handler,
405 void *user_data)
406{
407 DBusError err;
408 dbus->signal.vtable.unregister_function = dbus_path_unregister_function;
409 dbus->signal.vtable.message_function = dbus_message_function;
410 dbus->signal.signal_handler = handler;
411 dbus->signal.signal = signal;
412 dbus->signal.user_data = user_data;
413 dbus->signal.interface = interface;
414
415 if (!dbus_connection_register_object_path(dbus->conn, path,
416 &dbus->signal.vtable, dbus)) {
417 LOG(ERROR, "register_object_path failed");
418 return false;
419 }
420
421 dbus_error_init(&err);
422 dbus_bus_add_match(dbus->conn, rule, &err);
423 if (dbus_error_is_set(&err)) {
424 LOG(ERROR, "add_match failed: %s", err.message);
425 return false;
426 }
427
428 return true;
429}
430
David Sodmanbbcb0522014-09-19 10:34:07 -0700431void dbus_destroy(dbus_t* dbus)
432{
433 /* FIXME - not sure what the right counterpart to
434 dbus_bus_get() is, unref documentation is rather
435 unclear. Not a big issue but it would be nice to
436 clean up properly here */
437 /* dbus_connection_unref(dbus->conn); */
David Sodman8ef20062015-01-06 09:23:40 -0800438 if (dbus)
439 free(dbus);
440}
441
442void dbus_add_fd(dbus_t* dbus, fd_set* read_set, fd_set* exception_set)
443{
444 if (dbus->fd < 0)
445 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
446
447 if (dbus->fd >= 0) {
448 FD_SET(dbus->fd, read_set);
449 FD_SET(dbus->fd, exception_set);
450 }
451}
452
453int dbus_get_fd(dbus_t* dbus)
454{
455 if (dbus->fd < 0)
456 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
457
458 return dbus->fd;
459}
460
461
462void dbus_dispatch_io(dbus_t* dbus)
463{
464 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
465 while (dbus_connection_get_dispatch_status(dbus->conn)
466 == DBUS_DISPATCH_DATA_REMAINS) {
467 dbus_connection_dispatch(dbus->conn);
468 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700469}