Here are revised versions of the patches. The first one no longer
ignores luadoc.css, and the second uses SOCK_SEQPACKET instead of
SOCK_DGRAM. I tried to find a way to use SOCK_SEQPACKET's MSG_EOR flag
to send messages larger than 1023 bytes, but due to my inexperience with
sockets and the very limited documentation available online I wasn't
able to.
- Nathan
Nathan Weizenbaum wrote:
Julien Danjou wrote:
Hi Nathan,
Well, running "make" in the source dir should not create such file.
At least it does not here.
I think luadoc.css was an artifact of something else I was doing, but
make definitely generates awesome and awesome-devel symlinks for me
(using cmake 2.6-patch 1).
That's totally awesome.
But I think the 2 sockets approch is not so good; did you though about
using a bidirectionnal socket based on something like SOCK_SEQPAQUET?
No, I didn't. I hadn't worked with sockets in C before, so I just
tried to duplicate the existing architecture. SOCK_SEQPACKET does
sound better, though; I'll try re-implementing it using that.
- Nathan
>From a7899a5da275caeb49362c4864d6fce7ed34b79c Mon Sep 17 00:00:00 2001
From: Nathan Weizenbaum <[EMAIL PROTECTED]>
Date: Thu, 18 Sep 2008 21:09:50 -0700
Subject: [PATCH] gitignore: add binaries
Signed-off-by: Nathan Weizenbaum <[EMAIL PROTECTED]>
---
.gitignore | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
index 5bbaf3e..24481ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@
.*.sw?
build
.build*
+/awesome
+/awesome-client
--
1.6.0.1.267.gec3a.dirty
>From 308822ee1d1aa2bb505b30e80195e5f0e61fa5e4 Mon Sep 17 00:00:00 2001
From: Nathan Weizenbaum <[EMAIL PROTECTED]>
Date: Thu, 18 Sep 2008 21:48:55 -0700
Subject: [PATCH] awesome-client, socket, lua: make awesome-client into a true REPL
After recieving a command from awesome-client, awesome will send
the result of that command in return and awesome-client will print it out.
Signed-off-by: Nathan Weizenbaum <[EMAIL PROTECTED]>
---
awesome-client.c | 81 +++++++++++++++++++++++++++++++---------
common/socket.c | 2 +-
lua.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 163 insertions(+), 28 deletions(-)
diff --git a/awesome-client.c b/awesome-client.c
index 3af9c87..15121ac 100644
--- a/awesome-client.c
+++ b/awesome-client.c
@@ -41,6 +41,32 @@
#define MSG_NOSIGNAL 0
#endif
+struct sockaddr_un *addr;
+int csfd;
+
+/** Initialize the client and server socket connections.
+ * If something goes wrong, preserves errno.
+ * \return 0 if everything worked, 1 otherwise.
+ */
+static int
+init_sockets(void)
+{
+ return (csfd = socket_getclient()) < 0 ||
+ !(addr = socket_getaddr(getenv("DISPLAY"))) ||
+ connect(csfd, addr, sizeof(struct sockaddr_un)) == -1;
+}
+
+
+/** Close the client and server socket connections.
+ */
+static void
+close_sockets(void)
+{
+ close(csfd);
+ p_delete(&addr);
+}
+
+
/** Send a message to awesome.
* \param msg The message.
* \param msg_len The message length.
@@ -49,32 +75,43 @@
static int
send_msg(const char *msg, ssize_t msg_len)
{
- struct sockaddr_un *addr;
- int csfd, ret_value = EXIT_SUCCESS;
- csfd = socket_getclient();
- addr = socket_getaddr(getenv("DISPLAY"));
-
- if(!addr || csfd < 0)
- return EXIT_FAILURE;
-
- if(sendto(csfd, msg, msg_len, MSG_NOSIGNAL,
- (const struct sockaddr *) addr, sizeof(struct sockaddr_un)) == -1)
+ if(send(csfd, msg, msg_len, MSG_NOSIGNAL | MSG_EOR) == -1)
{
switch (errno)
{
case ENOENT:
- warn("can't write to %s", addr->sun_path);
- break;
+ warn("can't write to %s", addr->sun_path);
+ break;
default:
- warn("error sending datagram: %s", strerror(errno));
- }
- ret_value = errno;
+ warn("error sending packet: %s", strerror(errno));
+ }
+ return errno;
}
- close(csfd);
+ return EXIT_SUCCESS;
+}
- p_delete(&addr);
- return ret_value;
+
+/** Recieve a message from awesome.
+ */
+static void
+recv_msg(void)
+{
+ int r;
+ char buf[1024];
+
+ r = recv(csfd, buf, sizeof(buf) - 1, MSG_TRUNC);
+ if (r < 0)
+ {
+ warn("error recieving from UNIX domain socket: %s", strerror(errno));
+ return;
+ }
+
+ if (r >= 0)
+ {
+ buf[r] = '\0';
+ puts(buf);
+ }
}
@@ -114,6 +151,12 @@ main(int argc, char **argv)
else if(argc > 2)
exit_help(EXIT_SUCCESS);
+ if (init_sockets())
+ {
+ warn("can't connect to UNIX domain socket: %s", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
if(isatty(STDIN_FILENO))
{
char *display = getenv("DISPLAY");
@@ -126,6 +169,7 @@ main(int argc, char **argv)
msg[msg_len] = '\n';
msg[msg_len + 1] = '\0';
send_msg(msg, msg_len + 2);
+ recv_msg();
}
}
else
@@ -155,6 +199,7 @@ main(int argc, char **argv)
p_delete(&msg);
}
+ close_sockets();
return ret_value;
}
diff --git a/common/socket.c b/common/socket.c
index c44bbc1..840029c 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -79,7 +79,7 @@ socket_getclient(void)
{
int csfd;
- csfd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ csfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if(csfd < 0)
warn("error opening UNIX domain socket: %s", strerror(errno));
diff --git a/lua.c b/lua.c
index 0e49393..7c8329b 100644
--- a/lua.c
+++ b/lua.c
@@ -48,6 +48,7 @@
#include "event.h"
#include "layouts/tile.h"
#include "common/socket.h"
+#include "common/buffer.h"
extern awesome_t globalconf;
@@ -71,6 +72,7 @@ extern const struct luaL_reg awesome_keybinding_meta[];
static struct sockaddr_un *addr;
static ev_io csio = { .fd = -1 };
+struct ev_io csio2 = { .fd = -1 };
/** Add a global mouse binding. This binding will be available when you'll
* click on root window.
@@ -714,44 +716,130 @@ luaA_parserc(const char *confpatharg)
/** Parse a command.
* \param cmd The buffer to parse.
- * \return true on succes, false on failure.
+ * \return the number of elements pushed on the stack by the last statement in cmd.
+ * If there's an error, the message is pushed onto the stack and this returns 1.
*/
-static void
+static int
luaA_docmd(const char *cmd)
{
char *p;
+ int newtop, oldtop = lua_gettop(globalconf.L);
while((p = strchr(cmd, '\n')))
{
+ newtop = lua_gettop(globalconf.L);
+ lua_pop(globalconf.L, newtop - oldtop);
+ oldtop = newtop;
+
*p = '\0';
- luaA_dostring(globalconf.L, cmd);
+ if (luaL_dostring(globalconf.L, cmd))
+ {
+ warn("error executing Lua code: %s", lua_tostring(globalconf.L, -1));
+ return 1;
+ }
cmd = p + 1;
}
+ return lua_gettop(globalconf.L) - oldtop;
+}
+
+/** Pushes a Lua array containing the top n elements of the stack.
+ * \param n The number of elements to put in the array.
+ */
+static void
+luaA_array(int n)
+{
+ int i;
+ lua_createtable(globalconf.L, n, 0);
+ lua_insert(globalconf.L, -n - 1);
+
+ for (i = n; i > 0; i--)
+ lua_rawseti(globalconf.L, -i - 1, i);
+}
+
+/** Maps the top n elements of the stack to the result of
+ * applying a function to that element.
+ * \param n The number of elements to map.
+ * \luastack
+ * \lparam The function to map the elements by. This should be
+ * at position -(n + 1).
+ */
+static void
+luaA_map(int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ {
+ lua_pushvalue(globalconf.L, -n - 1); /* copy of the function */
+ lua_pushvalue(globalconf.L, -n - 1); /* value to map */
+ lua_pcall(globalconf.L, 1, 1, 0); /* call function */
+ lua_remove(globalconf.L, -n - 1); /* remove old value */
+ }
+ lua_remove(globalconf.L, -n - 1); /* remove function */
+}
+
+static void luaA_conn_cleanup(EV_P_ ev_io *w)
+{
+ ev_ref(EV_DEFAULT_UC);
+ ev_io_stop(EV_DEFAULT_UC_ w);
+ if (close(w->fd))
+ warn("error closing UNIX domain socket: %s", strerror(errno));
+ p_delete(&w);
}
static void
luaA_cb(EV_P_ ev_io *w, int revents)
{
char buf[1024];
- int r;
+ int r, els;
+ const char *s;
+ size_t len;
switch(r = recv(w->fd, buf, sizeof(buf)-1, MSG_TRUNC))
{
case -1:
warn("error reading UNIX domain socket: %s", strerror(errno));
- luaA_cs_cleanup();
- break;
- case 0:
+ case 0: /* 0 bytes are only transferred when the connection is closed */
+ luaA_conn_cleanup(EV_DEFAULT_UC_ w);
break;
default:
if(r >= ssizeof(buf))
break;
buf[r] = '\0';
- luaA_docmd(buf);
+ lua_getglobal(globalconf.L, "table");
+ lua_getfield(globalconf.L, -1, "concat");
+ lua_remove(globalconf.L, -2); /* remove table */
+
+ lua_getglobal(globalconf.L, "tostring");
+ els = luaA_docmd(buf);
+ luaA_map(els); /* map results to strings */
+ luaA_array(els); /* put strings in an array */
+
+ lua_pushstring(globalconf.L, "\t");
+ lua_pcall(globalconf.L, 2, 1, 0); /* concatenate results with tabs */
+
+ s = lua_tolstring(globalconf.L, -1, &len);
+
+ /* ignore ENOENT because the client doesn't create a socket for non-tty */
+ if (send(w->fd, s, len, 0) == -1 && errno != ENOENT)
+ warn("can't connect to client UNIX domain socket: %s", strerror(errno));
+
+ lua_pop(globalconf.L, 1); /* pop the string */
}
awesome_refresh(globalconf.connection);
}
+
+static void
+luaA_conn_cb(EV_P_ ev_io *w, int revents)
+{
+ ev_io *csio_conn = p_new(ev_io, 1);
+ int csfd = accept(w->fd, NULL, NULL);
+
+ ev_io_init(csio_conn, &luaA_cb, csfd, EV_READ);
+ ev_io_start(EV_DEFAULT_UC_ csio_conn);
+ ev_unref(EV_DEFAULT_UC);
+}
+
void
luaA_cs_init(void)
{
@@ -774,7 +862,9 @@ luaA_cs_init(void)
else
warn("error binding UNIX domain socket: %s", strerror(errno));
}
- ev_io_init(&csio, &luaA_cb, csfd, EV_READ);
+ listen(csfd, 10);
+
+ ev_io_init(&csio, &luaA_conn_cb, csfd, EV_READ);
ev_io_start(EV_DEFAULT_UC_ &csio);
ev_unref(EV_DEFAULT_UC);
}
--
1.6.0.1.267.gec3a.dirty