Replaced the fifo by socket to remote control vimb (#144).
authorDaniel Carl <danielcarl@gmx.de>
Tue, 30 Dec 2014 23:31:16 +0000 (00:31 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Wed, 31 Dec 2014 22:01:12 +0000 (23:01 +0100)
doc/vimb.1
examples/formfiller/formfiller
src/config.def.h
src/io.c
src/io.h
src/main.c
src/main.h

index ad351e7..8064877 100644 (file)
@@ -35,7 +35,10 @@ If the flag is used more than one time, the ordering is preserved when
 \fICMD\fP are executed. You could also pass several ex commands in one
 \fICMD\fP, if there are separated by "|".
 
-Example: vimb --cmd "set cookie-accept=origin|set header=Referer,DNT=1"
+Example:
+.EX
+vimb --cmd "set cookie-accept=origin|set header=Referer,DNT=1"
+.EE
 .TP
 .BI "\-c, \-\-config " "CONFIG-FILE"
 Use custom configuration given as \fICONFIG-FILE\fP. This will also be applied
@@ -46,14 +49,14 @@ on new spawned instances.
 of an XEmbed-aware application, that vimb will use as its parent.
 .TP
 .B \-d, \-\-dump
-Dump the current used fifo path to stdout in case vimb is started with \-f
-option. If vimb is started with `$(vimb -df > ~/vimb.fifo)' the full fifo
-path can be picked up from somewhere by `echo ":o github.com<CR>" > $(<
-~/vimb.fifo)'
-.TP
-.B \-f, \-\-fifo
-If given vimb will create a control fifo in vimb's config directory
-named 'vimb-fifo-{pid}'.
+Dump the current used socket path to stdout in case vimb is started with \-s
+option.
+
+Example:
+.EX
+sh -c "./vimb -s -d > ~/vimb.socket" &
+echo ":o github.com<CR>" | socat - unix-connect:$(< ~/vimb.socket)
+.EE
 .TP
 .B "\-h, \-\-help"
 Show help options.
@@ -62,6 +65,9 @@ Show help options.
 Run vimb in kiosk mode with nearly no keybindings, not inputbox and no context
 menu.
 .TP
+.B \-s, \-\-socket
+If given vimb will create a control socket.
+.TP
 .B "\-v, \-\-version"
 Print build and version information.
 .SH MODES
@@ -390,7 +396,7 @@ the rhs (right hand side) if this is available depends on the command. At the
 moment the count parts [N] of commands is parsed, but actual there does not
 exists any command that uses the count.
 .br
-Commands that are typed interactive (from inputbox or from fifo) are normally
+Commands that are typed interactive (from inputbox or from socket) are normally
 recorded into command history and register. To avoid this, the commands can be
 prefixed by one or more additional `:' or whitespace.
 .SS Command Line Editing
@@ -1447,14 +1453,14 @@ Contains the title of the current opened page.
 .B VIMB_PID
 Contains the pid of the running vimb instance.
 .TP
+.B VIMB_SOCKET
+Holds the full path to the control socket, if vimb is compiled with SOCKET
+feature and started with `--socket' option.
+.TP
 .B VIMB_XID
 Holds the X-Window id of the vim window or of the embedding window if vimb is
 started with -e option.
 .TP
-.B VIMB_FILE
-Holds the full path to the control fifo, if vimb is compiled with FIFO feature
-and started with `--fifo' option.
-.TP
 .B http_proxy
 If this variable is set to an none empty value, and the configuration option
 `proxy' is enabled, this will be used as http proxy. If the proxy URL has no
index 2f9a455..e0d5f99 100755 (executable)
@@ -41,16 +41,16 @@ fillform() {
     # make sure we are in normal mode and fill in the form data
     # use :: to not save the secrets into vimb command history or into the
     # last ex command register ":
-    echo "<Esc>::e! _vbform.fill($data);<CR>" > $VIMB_FIFO
+    echo "<Esc>::e! _vbform.fill($data);<CR>" | socat - UNIX-CONNECT:$VIMB_SOCKET
 }
 
 # check if uri is given
 if [ -z "$uri" ]; then
     die 'No URI given'
 fi
-# check if the script is run from vimb with fifo support enabled
-if [ -z "$VIMB_FIFO" ] || [ ! -p "$VIMB_FIFO" ]; then
-    die 'This script must be run from vimb with fifo support'
+# check if the script is run from vimb with socket support enabled
+if [ -z "$VIMB_SOCKET" ] || [ ! -S "$VIMB_SOCKET" ]; then
+    die 'This script must be run from vimb with socket support'
 fi
 
 # extract the domain part without ports from given uri
index ce0e5cb..4690534 100644 (file)
@@ -52,8 +52,8 @@
 #define FEATURE_AUTOCMD
 /* enable the :auto-response-header feature */
 #define FEATURE_ARH
-/* allow to use fifo to remote control vimb */
-#define FEATURE_FIFO
+/* allow to use socket to remote control vimb */
+#define FEATURE_SOCKET
 
 /* time in seconds after that message will be removed from inputbox if the
  * message where only temporary */
index 3603c0d..c67764b 100644 (file)
--- a/src/io.c
+++ b/src/io.c
  */
 
 #include "config.h"
-#ifdef FEATURE_FIFO
+#ifdef FEATURE_SOCKET
 #include "io.h"
 #include "main.h"
 #include "map.h"
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
 
 extern VbCore vb;
 
-static gboolean fifo_watch(GIOChannel *gio, GIOCondition condition);
+static gboolean socket_accept(GIOChannel *chan);
+static gboolean socket_watch(GIOChannel *chan);
 
 
-gboolean io_init_fifo(const char *name)
+gboolean io_init_socket(const char *name)
 {
     char *fname, *path;
+    int sock;
+    struct sockaddr_un local;
 
-    /* create fifo in directory as vimb-fifo-$PID */
-    fname = g_strdup_printf(PROJECT "-fifo-%s", name);
+    /* create socket in directory as vimb-socket-$PID */
+    fname = g_strdup_printf(PROJECT "-socket-%s", name);
     path  = g_build_filename(g_get_user_config_dir(), PROJECT, fname, NULL);
     g_free(fname);
 
@@ -45,26 +51,35 @@ gboolean io_init_fifo(const char *name)
         unlink(path);
     }
 
-    if (mkfifo(path, 0666) == 0) {
-        GError *error    = NULL;
-        /* use r+ to avoid blocking caused by wait of a writer */
-        GIOChannel *chan = g_io_channel_new_file(path, "r+", &error);
+    sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        g_warning("Can't create socket %s", path);
+    }
+
+    /* prepare socket address */
+    local.sun_family = AF_UNIX;
+    strcpy(local.sun_path, path);
+
+    if (bind(sock, (struct sockaddr*)&local, sizeof(local)) != -1
+        && listen(sock, 5) >= 0
+    ) {
+        GIOChannel *chan = g_io_channel_unix_new(sock);
         if (chan) {
-            if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc)fifo_watch, NULL)) {
-                /* don't free path - because we want to keep the value in
-                 * vb.state.fifo_path still accessible */
-                vb.state.fifo_path = path;
-                g_setenv("VIMB_FIFO", path, TRUE);
-
-                return true;
-            }
-        } else {
-            g_warning ("Can't open fifo: %s", error->message);
-            g_error_free(error);
+            g_io_channel_set_encoding(chan, NULL, NULL);
+            g_io_channel_set_buffered(chan, false);
+            g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc)socket_accept, chan);
+            /* don't free path - because we want to keep the value in
+             * vb.state.socket_path still accessible */
+            vb.state.socket_path = path;
+            g_setenv("VIMB_SOCKET", path, true);
+
+            return true;
         }
     } else {
-        g_warning("Can't create fifo %s", path);
+        g_warning("no bind");
     }
+
+    g_warning("Could not listen on %s: %s", path, strerror(errno));
     g_free(path);
 
     return false;
@@ -72,44 +87,81 @@ gboolean io_init_fifo(const char *name)
 
 void io_cleanup(void)
 {
-    if (vb.state.fifo_path) {
-        if (unlink(vb.state.fifo_path) == -1) {
-            g_warning("Can't remove fifo %s", vb.state.fifo_path);
+    if (vb.state.socket_path) {
+        if (unlink(vb.state.socket_path) == -1) {
+            g_warning("Can't remove socket %s", vb.state.socket_path);
         }
-        g_free(vb.state.fifo_path);
-        vb.state.fifo_path = NULL;
+        g_free(vb.state.socket_path);
+        vb.state.socket_path = NULL;
     }
 }
 
-static gboolean fifo_watch(GIOChannel *gio, GIOCondition condition)
+static gboolean socket_accept(GIOChannel *chan)
 {
-    char *line;
-    GIOStatus ret;
-    GError *err = NULL;
+    struct sockaddr_un remote;
+    guint size = sizeof(remote);
+    GIOChannel *iochan;
+    int clientsock;
 
-    if (condition & G_IO_HUP) {
-        g_error("fifo: read end of pipe died");
-    }
+    clientsock = accept(g_io_channel_unix_get_fd(chan), (struct sockaddr *)&remote, &size);
 
-    if (!gio) {
-        g_error("fifo: GIOChannel broken");
+    if ((iochan = g_io_channel_unix_new(clientsock))) {
+        g_io_channel_set_encoding(iochan, NULL, NULL);
+        g_io_add_watch(iochan, G_IO_IN|G_IO_HUP, (GIOFunc)socket_watch, iochan);
     }
+    return true;
+}
 
-    ret = g_io_channel_read_line(gio, &line, NULL, NULL, &err);
-    if (ret == G_IO_STATUS_ERROR) {
-        g_error("fifo: error reading from fifo: %s", err->message);
-        g_error_free(err);
+static gboolean socket_watch(GIOChannel *chan)
+{
+    GIOStatus ret;
+    GError *error = NULL;
+    char *line, *inputtext;
+    gsize len;
+
+    ret = g_io_channel_read_line(chan, &line, &len, NULL, &error);
+    if (ret == G_IO_STATUS_ERROR || ret == G_IO_STATUS_EOF) {
+        if (ret == G_IO_STATUS_ERROR) {
+            g_warning("Error reading: %s", error->message);
+            g_error_free(&error);
+        }
+
+        /* shutdown and remove the client channel */
+        ret = g_io_channel_shutdown(chan, true, &error);
+        g_io_channel_unref(chan);
+
+        if (ret == G_IO_STATUS_ERROR) {
+            g_warning("Error closing: %s", error->message);
+            g_error_free(&error);
+        }
+        return false;
     }
 
     /* simulate the typed flag to allow to record the commands in history */
     vb.state.typed = true;
 
+    /* run the commands */
     map_handle_string(line, true);
     g_free(line);
 
     /* unset typed flag */
     vb.state.typed = false;
 
+    /* We assume that the commands result is still available in the inputbox,
+     * so the whole inputbox content is written to the socket. */
+    inputtext = vb_get_input_text();
+    ret       = g_io_channel_write_chars(chan, inputtext, -1, &len, &error);
+    if (ret == G_IO_STATUS_ERROR) {
+        g_warning("Error writing: %s", error->message);
+        g_error_free(&error);
+    }
+    if (g_io_channel_flush(chan, &error) == G_IO_STATUS_ERROR) {
+        g_warning("Error flushing: %s", error->message);
+        g_error_free(&error);
+    }
+
+    g_free(inputtext);
+
     return true;
 }
 
index fdddbf5..fa131ac 100644 (file)
--- a/src/io.h
+++ b/src/io.h
  */
 
 #include "config.h"
-#ifdef FEATURE_FIFO
+#ifdef FEATURE_SOCKET
 
 #ifndef _IO_H
 #define _IO_H
 
 #include <glib.h>
 
-gboolean io_init_fifo(const char *dir);
+gboolean io_init_socket(const char *name);
 void io_cleanup(void);
 
 #endif /* end of include guard: _IO_H */
index 509d214..2c3c8e3 100644 (file)
@@ -232,8 +232,8 @@ gboolean vb_load_uri(const Arg *arg)
             + (vb.embed ? 2 : 0)
             + (vb.config.file ? 2 : 0)
             + (vb.config.kioskmode ? 1 : 0)
-#ifdef FEATURE_FIFO
-            + (vb.config.fifo ? 1 : 0)
+#ifdef FEATURE_SOCKET
+            + (vb.config.socket ? 1 : 0)
 #endif
             + g_slist_length(vb.config.cmdargs) * 2,
             sizeof(char *)
@@ -258,9 +258,9 @@ gboolean vb_load_uri(const Arg *arg)
         if (vb.config.kioskmode) {
             cmd[i++] = "-k";
         }
-#ifdef FEATURE_FIFO
-        if (vb.config.fifo) {
-            cmd[i++] = "-f";
+#ifdef FEATURE_SOCKET
+        if (vb.config.socket) {
+            cmd[i++] = "-s";
         }
 #endif
         cmd[i++] = uri;
@@ -1558,7 +1558,7 @@ static void vb_cleanup(void)
 #ifdef FEATURE_ARH
     arh_free(vb.config.autoresponseheader);
 #endif
-#ifdef FEATURE_FIFO
+#ifdef FEATURE_SOCKET
     io_cleanup();
 #endif
     g_free(vb.state.pid_str);
@@ -1582,7 +1582,7 @@ int main(int argc, char *argv[])
 {
     static char *winid   = NULL;
     static gboolean ver  = false;
-#ifdef FEATURE_FIFO
+#ifdef FEATURE_SOCKET
     static gboolean dump = false;
 #endif
     static GError *err;
@@ -1591,9 +1591,9 @@ int main(int argc, char *argv[])
         {"cmd", 'C', 0, G_OPTION_ARG_CALLBACK, autocmdOptionArgFunc, "Ex command run before first page is loaded", NULL},
         {"config", 'c', 0, G_OPTION_ARG_FILENAME, &vb.config.file, "Custom configuration file", NULL},
         {"embed", 'e', 0, G_OPTION_ARG_STRING, &winid, "Reparents to window specified by xid", NULL},
-#ifdef FEATURE_FIFO
-        {"dump", 'd', 0, G_OPTION_ARG_NONE, &dump, "Dump the fifo path to stdout", NULL},
-        {"fifo", 'f', 0, G_OPTION_ARG_NONE, &vb.config.fifo, "Create control fifo", NULL},
+#ifdef FEATURE_SOCKET
+        {"dump", 'd', 0, G_OPTION_ARG_NONE, &dump, "Dump the socket path to stdout", NULL},
+        {"socket", 's', 0, G_OPTION_ARG_NONE, &vb.config.socket, "Create control socket", NULL},
 #endif
         {"kiosk", 'k', 0, G_OPTION_ARG_NONE, &vb.config.kioskmode, "Run in kiosk mode", NULL},
         {"version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Print version", NULL},
@@ -1647,15 +1647,15 @@ int main(int argc, char *argv[])
         vb_load_uri(&(Arg){VB_TARGET_CURRENT, argv[argc - 1]});
     }
 
-#ifdef FEATURE_FIFO
-    /* setup the control fifo - quit vimb if this failed */
-    if (vb.config.fifo && !io_init_fifo(vb.state.pid_str)) {
+#ifdef FEATURE_SOCKET
+    /* setup the control socket - quit vimb if this failed */
+    if (vb.config.socket && !io_init_socket(vb.state.pid_str)) {
         /* cleanup memory */
         vb_cleanup();
         return EXIT_FAILURE;
     }
-    if (dump && vb.state.fifo_path) {
-        printf("%s\n", vb.state.fifo_path);
+    if (dump && vb.state.socket_path) {
+        printf("%s\n", vb.state.socket_path);
         fflush(NULL);
     }
 #endif
index 4c4349d..6a71b3d 100644 (file)
@@ -313,6 +313,7 @@ typedef struct {
     int             search_matches;         /* number of matches search results */
 #endif
     char            *fifo_path;             /* holds the path to the control fifo */
+    char            *socket_path;           /* holds the path to the control socket */
     char            *pid_str;               /* holds the pid as string */
 } State;
 
@@ -339,8 +340,8 @@ typedef struct {
     float        default_zoom;    /* default zoomlevel that is applied on zz zoom reset */
     gboolean     kioskmode;
     gboolean     input_autohide;  /* indicates if the inputbox should be hidden if it's empty */
-#ifdef FEATURE_FIFO
-    gboolean     fifo;            /* indicates if the fifo is used */
+#ifdef FEATURE_SOCKET
+    gboolean     socket;          /* indicates if the socket is used */
 #endif
 #ifdef FEATURE_HSTS
     HSTSProvider *hsts_provider;  /* the hsts session feature that is added to soup session */