comparison src/remote.c @ 1554:a96a20c7feb1

improved remote protocol to allow bidirectional communication
author nadvornik
date Mon, 20 Apr 2009 19:44:50 +0000
parents 24a12aa0cb54
children 3840882253fe
comparison
equal deleted inserted replaced
1553:626adbb26387 1554:a96a20c7feb1
65 65
66 rc = client->rc; 66 rc = client->rc;
67 67
68 if (condition & G_IO_IN) 68 if (condition & G_IO_IN)
69 { 69 {
70 GList *queue = NULL;
71 GList *work;
72 gchar *buffer = NULL; 70 gchar *buffer = NULL;
73 GError *error = NULL; 71 GError *error = NULL;
74 gsize termpos; 72 gsize termpos;
75 73
76 while ((status = g_io_channel_read_line(source, &buffer, NULL, &termpos, &error)) == G_IO_STATUS_NORMAL) 74 while ((status = g_io_channel_read_line(source, &buffer, NULL, &termpos, &error)) == G_IO_STATUS_NORMAL)
79 { 77 {
80 buffer[termpos] = '\0'; 78 buffer[termpos] = '\0';
81 79
82 if (strlen(buffer) > 0) 80 if (strlen(buffer) > 0)
83 { 81 {
84 queue = g_list_append(queue, buffer); 82 if (rc->read_func) rc->read_func(rc, buffer, source, rc->read_data);
83 g_io_channel_write_chars(source, "\n", -1, NULL, NULL); /* empty line finishes the command */
84 g_io_channel_flush(source, NULL);
85 } 85 }
86 else 86 g_free(buffer);
87 {
88 g_free(buffer);
89 }
90 87
91 buffer = NULL; 88 buffer = NULL;
92 } 89 }
93 } 90 }
94 91
95 if (error) 92 if (error)
96 { 93 {
97 log_printf("error reading socket: %s\n", error->message); 94 log_printf("error reading socket: %s\n", error->message);
98 g_error_free(error); 95 g_error_free(error);
99 } 96 }
100
101 work = queue;
102 while (work)
103 {
104 gchar *command = work->data;
105 work = work->next;
106
107 if (rc->read_func) rc->read_func(rc, command, rc->read_data);
108 g_free(command);
109 }
110
111 g_list_free(queue);
112 } 97 }
113 98
114 if (condition & G_IO_HUP || status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR) 99 if (condition & G_IO_HUP || status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
115 { 100 {
116 rc->clients = g_list_remove(rc->clients, client); 101 rc->clients = g_list_remove(rc->clients, client);
277 rc = g_new0(RemoteConnection, 1); 262 rc = g_new0(RemoteConnection, 1);
278 rc->server = FALSE; 263 rc->server = FALSE;
279 rc->fd = fd; 264 rc->fd = fd;
280 rc->path = g_strdup(path); 265 rc->path = g_strdup(path);
281 266
282 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */
283 remote_client_send(rc, "\n");
284
285 return rc; 267 return rc;
286 } 268 }
287 269
288 static sig_atomic_t sigpipe_occured = FALSE; 270 static sig_atomic_t sigpipe_occured = FALSE;
289 271
294 276
295 static gboolean remote_client_send(RemoteConnection *rc, const gchar *text) 277 static gboolean remote_client_send(RemoteConnection *rc, const gchar *text)
296 { 278 {
297 struct sigaction new_action, old_action; 279 struct sigaction new_action, old_action;
298 gboolean ret = FALSE; 280 gboolean ret = FALSE;
281 GError *error = NULL;
282 GIOChannel *channel;
299 283
300 if (!rc || rc->server) return FALSE; 284 if (!rc || rc->server) return FALSE;
301 if (!text) return TRUE; 285 if (!text) return TRUE;
302 286
303 sigpipe_occured = FALSE; 287 sigpipe_occured = FALSE;
307 new_action.sa_flags = 0; 291 new_action.sa_flags = 0;
308 292
309 /* setup our signal handler */ 293 /* setup our signal handler */
310 sigaction(SIGPIPE, &new_action, &old_action); 294 sigaction(SIGPIPE, &new_action, &old_action);
311 295
312 if (write(rc->fd, text, strlen(text)) == -1 || 296 channel = g_io_channel_unix_new(rc->fd);
313 write(rc->fd, "\n", 1) == -1) 297
314 { 298 g_io_channel_write_chars(channel, text, -1, NULL, &error);
315 if (sigpipe_occured) 299 g_io_channel_write_chars(channel, "\n", -1, NULL, &error);
316 { 300 g_io_channel_flush(channel, &error);
317 log_printf("SIGPIPE writing to socket: %s\n", rc->path); 301
318 } 302 if (error)
319 else 303 {
320 { 304 log_printf("error reading socket: %s\n", error->message);
321 log_printf("error writing to socket: %s\n", strerror(errno)); 305 g_error_free(error);
322 }
323 ret = FALSE;; 306 ret = FALSE;;
324 } 307 }
325 else 308 else
326 { 309 {
327 ret = TRUE; 310 ret = TRUE;
328 } 311 }
312
313 if (ret)
314 {
315 gchar *buffer = NULL;
316 gsize termpos;
317 while (g_io_channel_read_line(channel, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL)
318 {
319 if (buffer)
320 {
321 if (buffer[0] == '\n') /* empty line finishes the command */
322 {
323 g_free(buffer);
324 break;
325 }
326 buffer[termpos] = '\0';
327 printf("%s\n", buffer);
328 g_free(buffer);
329 buffer = NULL;
330 }
331 }
332
333 if (error)
334 {
335 log_printf("error reading socket: %s\n", error->message);
336 g_error_free(error);
337 ret = FALSE;
338 }
339 }
340
329 341
330 /* restore the original signal handler */ 342 /* restore the original signal handler */
331 sigaction(SIGPIPE, &old_action, NULL); 343 sigaction(SIGPIPE, &old_action, NULL);
332 344 g_io_channel_unref(channel);
333 return ret; 345 return ret;
334 } 346 }
335 347
336 void remote_close(RemoteConnection *rc) 348 void remote_close(RemoteConnection *rc)
337 { 349 {
358 *----------------------------------------------------------------------------- 370 *-----------------------------------------------------------------------------
359 * remote functions 371 * remote functions
360 *----------------------------------------------------------------------------- 372 *-----------------------------------------------------------------------------
361 */ 373 */
362 374
363 static void gr_image_next(const gchar *text, gpointer data) 375 static void gr_image_next(const gchar *text, GIOChannel *channel, gpointer data)
364 { 376 {
365 layout_image_next(NULL); 377 layout_image_next(NULL);
366 } 378 }
367 379
368 static void gr_image_prev(const gchar *text, gpointer data) 380 static void gr_image_prev(const gchar *text, GIOChannel *channel, gpointer data)
369 { 381 {
370 layout_image_prev(NULL); 382 layout_image_prev(NULL);
371 } 383 }
372 384
373 static void gr_image_first(const gchar *text, gpointer data) 385 static void gr_image_first(const gchar *text, GIOChannel *channel, gpointer data)
374 { 386 {
375 layout_image_first(NULL); 387 layout_image_first(NULL);
376 } 388 }
377 389
378 static void gr_image_last(const gchar *text, gpointer data) 390 static void gr_image_last(const gchar *text, GIOChannel *channel, gpointer data)
379 { 391 {
380 layout_image_last(NULL); 392 layout_image_last(NULL);
381 } 393 }
382 394
383 static void gr_fullscreen_toggle(const gchar *text, gpointer data) 395 static void gr_fullscreen_toggle(const gchar *text, GIOChannel *channel, gpointer data)
384 { 396 {
385 layout_image_full_screen_toggle(NULL); 397 layout_image_full_screen_toggle(NULL);
386 } 398 }
387 399
388 static void gr_fullscreen_start(const gchar *text, gpointer data) 400 static void gr_fullscreen_start(const gchar *text, GIOChannel *channel, gpointer data)
389 { 401 {
390 layout_image_full_screen_start(NULL); 402 layout_image_full_screen_start(NULL);
391 } 403 }
392 404
393 static void gr_fullscreen_stop(const gchar *text, gpointer data) 405 static void gr_fullscreen_stop(const gchar *text, GIOChannel *channel, gpointer data)
394 { 406 {
395 layout_image_full_screen_stop(NULL); 407 layout_image_full_screen_stop(NULL);
396 } 408 }
397 409
398 static void gr_slideshow_start_rec(const gchar *text, gpointer data) 410 static void gr_slideshow_start_rec(const gchar *text, GIOChannel *channel, gpointer data)
399 { 411 {
400 GList *list; 412 GList *list;
401 FileData *dir_fd = file_data_new_simple(text); 413 FileData *dir_fd = file_data_new_simple(text);
402 list = filelist_recursive(dir_fd); 414 list = filelist_recursive(dir_fd);
403 file_data_unref(dir_fd); 415 file_data_unref(dir_fd);
405 //printf("length: %d\n", g_list_length(list)); 417 //printf("length: %d\n", g_list_length(list));
406 layout_image_slideshow_stop(NULL); 418 layout_image_slideshow_stop(NULL);
407 layout_image_slideshow_start_from_list(NULL, list); 419 layout_image_slideshow_start_from_list(NULL, list);
408 } 420 }
409 421
410 static void gr_slideshow_toggle(const gchar *text, gpointer data) 422 static void gr_slideshow_toggle(const gchar *text, GIOChannel *channel, gpointer data)
411 { 423 {
412 layout_image_slideshow_toggle(NULL); 424 layout_image_slideshow_toggle(NULL);
413 } 425 }
414 426
415 static void gr_slideshow_start(const gchar *text, gpointer data) 427 static void gr_slideshow_start(const gchar *text, GIOChannel *channel, gpointer data)
416 { 428 {
417 layout_image_slideshow_start(NULL); 429 layout_image_slideshow_start(NULL);
418 } 430 }
419 431
420 static void gr_slideshow_stop(const gchar *text, gpointer data) 432 static void gr_slideshow_stop(const gchar *text, GIOChannel *channel, gpointer data)
421 { 433 {
422 layout_image_slideshow_stop(NULL); 434 layout_image_slideshow_stop(NULL);
423 } 435 }
424 436
425 static void gr_slideshow_delay(const gchar *text, gpointer data) 437 static void gr_slideshow_delay(const gchar *text, GIOChannel *channel, gpointer data)
426 { 438 {
427 gdouble n; 439 gdouble n;
428 440
429 n = g_ascii_strtod(text, NULL); 441 n = g_ascii_strtod(text, NULL);
430 if (n < SLIDESHOW_MIN_SECONDS || n > SLIDESHOW_MAX_SECONDS) 442 if (n < SLIDESHOW_MIN_SECONDS || n > SLIDESHOW_MAX_SECONDS)
434 return; 446 return;
435 } 447 }
436 options->slideshow.delay = (gint)(n * 10.0 + 0.01); 448 options->slideshow.delay = (gint)(n * 10.0 + 0.01);
437 } 449 }
438 450
439 static void gr_tools_show(const gchar *text, gpointer data) 451 static void gr_tools_show(const gchar *text, GIOChannel *channel, gpointer data)
440 { 452 {
441 gboolean popped; 453 gboolean popped;
442 gboolean hidden; 454 gboolean hidden;
443 455
444 if (layout_tools_float_get(NULL, &popped, &hidden) && hidden) 456 if (layout_tools_float_get(NULL, &popped, &hidden) && hidden)
445 { 457 {
446 layout_tools_float_set(NULL, popped, FALSE); 458 layout_tools_float_set(NULL, popped, FALSE);
447 } 459 }
448 } 460 }
449 461
450 static void gr_tools_hide(const gchar *text, gpointer data) 462 static void gr_tools_hide(const gchar *text, GIOChannel *channel, gpointer data)
451 { 463 {
452 gboolean popped; 464 gboolean popped;
453 gboolean hidden; 465 gboolean hidden;
454 466
455 if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden) 467 if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden)
463 exit_program(); 475 exit_program();
464 476
465 return FALSE; 477 return FALSE;
466 } 478 }
467 479
468 static void gr_quit(const gchar *text, gpointer data) 480 static void gr_quit(const gchar *text, GIOChannel *channel, gpointer data)
469 { 481 {
470 /* schedule exit when idle, if done from within a 482 /* schedule exit when idle, if done from within a
471 * remote handler remote_close will crash 483 * remote handler remote_close will crash
472 */ 484 */
473 g_idle_add(gr_quit_idle_cb, NULL); 485 g_idle_add(gr_quit_idle_cb, NULL);
474 } 486 }
475 487
476 static void gr_file_load(const gchar *text, gpointer data) 488 static void gr_file_load(const gchar *text, GIOChannel *channel, gpointer data)
477 { 489 {
478 gchar *filename = expand_tilde(text); 490 gchar *filename = expand_tilde(text);
479 491
480 if (isfile(filename)) 492 if (isfile(filename))
481 { 493 {
498 } 510 }
499 511
500 g_free(filename); 512 g_free(filename);
501 } 513 }
502 514
503 static void gr_config_load(const gchar *text, gpointer data) 515 static void gr_config_load(const gchar *text, GIOChannel *channel, gpointer data)
504 { 516 {
505 gchar *filename = expand_tilde(text); 517 gchar *filename = expand_tilde(text);
506 518
507 if (isfile(filename)) 519 if (isfile(filename))
508 { 520 {
514 } 526 }
515 527
516 g_free(filename); 528 g_free(filename);
517 } 529 }
518 530
519 static void gr_file_view(const gchar *text, gpointer data) 531 static void gr_file_view(const gchar *text, GIOChannel *channel, gpointer data)
520 { 532 {
521 gchar *filename = expand_tilde(text); 533 gchar *filename = expand_tilde(text);
522 534
523 view_window_new(file_data_new_simple(filename)); 535 view_window_new(file_data_new_simple(filename));
524 g_free(filename); 536 g_free(filename);
525 } 537 }
526 538
527 static void gr_list_clear(const gchar *text, gpointer data) 539 static void gr_list_clear(const gchar *text, GIOChannel *channel, gpointer data)
528 { 540 {
529 RemoteData *remote_data = data; 541 RemoteData *remote_data = data;
530 542
531 if (remote_data->command_collection) 543 if (remote_data->command_collection)
532 { 544 {
533 collection_unref(remote_data->command_collection); 545 collection_unref(remote_data->command_collection);
534 remote_data->command_collection = NULL; 546 remote_data->command_collection = NULL;
535 } 547 }
536 } 548 }
537 549
538 static void gr_list_add(const gchar *text, gpointer data) 550 static void gr_list_add(const gchar *text, GIOChannel *channel, gpointer data)
539 { 551 {
540 RemoteData *remote_data = data; 552 RemoteData *remote_data = data;
541 gboolean new = TRUE; 553 gboolean new = TRUE;
542 554
543 if (!remote_data->command_collection) 555 if (!remote_data->command_collection)
563 layout_image_set_collection(NULL, remote_data->command_collection, 575 layout_image_set_collection(NULL, remote_data->command_collection,
564 collection_get_first(remote_data->command_collection)); 576 collection_get_first(remote_data->command_collection));
565 } 577 }
566 } 578 }
567 579
568 static void gr_raise(const gchar *text, gpointer data) 580 static void gr_raise(const gchar *text, GIOChannel *channel, gpointer data)
569 { 581 {
570 LayoutWindow *lw = NULL; 582 LayoutWindow *lw = NULL;
571 583
572 if (layout_valid(&lw)) 584 if (layout_valid(&lw))
573 { 585 {
577 589
578 typedef struct _RemoteCommandEntry RemoteCommandEntry; 590 typedef struct _RemoteCommandEntry RemoteCommandEntry;
579 struct _RemoteCommandEntry { 591 struct _RemoteCommandEntry {
580 gchar *opt_s; 592 gchar *opt_s;
581 gchar *opt_l; 593 gchar *opt_l;
582 void (*func)(const gchar *text, gpointer data); 594 void (*func)(const gchar *text, GIOChannel *channel, gpointer data);
583 gboolean needs_extra; 595 gboolean needs_extra;
584 gboolean prefer_command_line; 596 gboolean prefer_command_line;
585 gchar *description; 597 gchar *description;
586 }; 598 };
587 599
648 } 660 }
649 661
650 return NULL; 662 return NULL;
651 } 663 }
652 664
653 static void remote_cb(RemoteConnection *rc, const gchar *text, gpointer data) 665 static void remote_cb(RemoteConnection *rc, const gchar *text, GIOChannel *channel, gpointer data)
654 { 666 {
655 RemoteCommandEntry *entry; 667 RemoteCommandEntry *entry;
656 const gchar *offset; 668 const gchar *offset;
657 669
658 entry = remote_command_find(text, &offset); 670 entry = remote_command_find(text, &offset);
659 if (entry && entry->func) 671 if (entry && entry->func)
660 { 672 {
661 entry->func(offset, data); 673 entry->func(offset, channel, data);
662 } 674 }
663 else 675 else
664 { 676 {
665 log_printf("unknown remote command:%s\n", text); 677 log_printf("unknown remote command:%s\n", text);
666 } 678 }