lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Some time ago I wrote a unix syslog replacement in lua. 
The main rationale was pattern matching abilities in an embedded environment.

However, in order to do this one must be able to open and listen on a unix datagram socket. 
Hence the attached patch to the (undocumented?) unix socket API. In case it could prove useful.

Enjoy
/Flemming
--- src/unix.c.orig	2012-03-17 08:04:37.564875006 +0100
+++ src/unix.c	2012-03-17 08:40:40.943453998 +0100
@@ -13,16 +13,19 @@
 #include "socket.h"
 #include "options.h"
 #include "unix.h"
+#include "udp.h"
 #include <sys/un.h> 
 
 /*=========================================================================*\
 * Internal function prototypes
 \*=========================================================================*/
-static int global_create(lua_State *L);
+static int global_create_stream(lua_State *L);
+static int global_create_dgram(lua_State *L);
 static int meth_connect(lua_State *L);
 static int meth_listen(lua_State *L);
 static int meth_bind(lua_State *L);
 static int meth_send(lua_State *L);
+static int meth_sendto(lua_State *L);
 static int meth_shutdown(lua_State *L);
 static int meth_receive(lua_State *L);
 static int meth_accept(lua_State *L);
@@ -53,6 +56,7 @@
     {"listen",      meth_listen},
     {"receive",     meth_receive},
     {"send",        meth_send},
+    {"sendto",      meth_sendto},
     {"setfd",       meth_setfd},
     {"setoption",   meth_setoption},
     {"setpeername", meth_connect},
@@ -72,7 +76,8 @@
 
 /* our socket creation function */
 static luaL_reg func[] = {
-    {"unix", global_create},
+    {"unix", global_create_stream},
+    {"unix_dgram", global_create_dgram},
     {NULL,          NULL}
 };
 
@@ -80,28 +85,71 @@
 /*-------------------------------------------------------------------------*\
 * Initializes module
 \*-------------------------------------------------------------------------*/
-int luaopen_socket_unix(lua_State *L) {
+static int unix_open(lua_State *L, const char *name) {
     /* create classes */
     auxiliar_newclass(L, "unix{master}", un);
     auxiliar_newclass(L, "unix{client}", un);
     auxiliar_newclass(L, "unix{server}", un);
+    auxiliar_newclass(L, "unix{dgram}", un);
+    auxiliar_newclass(L, "unix{dgbound}", un);
     /* create class groups */
-    auxiliar_add2group(L, "unix{master}", "unix{any}");
-    auxiliar_add2group(L, "unix{client}", "unix{any}");
-    auxiliar_add2group(L, "unix{server}", "unix{any}");
+    auxiliar_add2group(L, "unix{master}",  "unix{any}");
+    auxiliar_add2group(L, "unix{client}",  "unix{any}");
+    auxiliar_add2group(L, "unix{server}",  "unix{any}");
+    auxiliar_add2group(L, "unix{dgram}",   "unix{any}");
+    auxiliar_add2group(L, "unix{dgram}",   "unix{bindable}");
+    auxiliar_add2group(L, "unix{master}",  "unix{bindable}");
+    auxiliar_add2group(L, "unix{client}",  "unix{readable}");
+    auxiliar_add2group(L, "unix{dgbound}", "unix{readable}");
+
     /* make sure the function ends up in the package table */
     luaL_openlib(L, "socket", func, 0);
     /* return the function instead of the 'socket' table */
-    lua_pushstring(L, "unix");
+    lua_pushstring(L, name);
     lua_gettable(L, -2);
     return 1;
 }
+int luaopen_socket_unix(lua_State *L) {
+    return unix_open(L, "unix");
+}
+int luaopen_socket_unix_dgram(lua_State *L) {
+    return unix_open(L, "unix_dgram");
+}
+
 
 /*=========================================================================*\
 * Lua methods
 \*=========================================================================*/
 /*-------------------------------------------------------------------------*\
-* Just call buffered IO methods
+* Send data through unix dgram socket
+\*-------------------------------------------------------------------------*/
+static int meth_sendto(lua_State *L) {
+    p_unix un = (p_unix) auxiliar_checkclass(L, "unix{dgram}", 1);
+    size_t count, sent = 0;
+    const char *data = luaL_checklstring(L, 2, &count);
+    const char *sock = luaL_checkstring(L, 3);
+    p_timeout tm = &un->tm;
+    struct sockaddr_un addr;
+    int err;
+    memset(&addr, 0, sizeof(addr));
+
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sock, 100);
+    addr.sun_path[100] = 0;
+    timeout_markstart(tm);
+    err = socket_sendto(&un->sock, data, count, &sent, 
+            (SA *) &addr, sizeof(addr), tm);
+    if (err != IO_DONE) {
+        lua_pushnil(L);
+        lua_pushstring(L, socket_strerror(err));
+        return 2;
+    }
+    lua_pushnumber(L, sent);
+    return 1;
+}
+
+/*-------------------------------------------------------------------------*\
+* Just call buffered IO methods (almost)
 \*-------------------------------------------------------------------------*/
 static int meth_send(lua_State *L) {
     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
@@ -109,8 +157,26 @@
 }
 
 static int meth_receive(lua_State *L) {
-    p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
-    return buffer_meth_receive(L, &un->buf);
+    p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{readable}", 1);
+    if (auxiliar_getclassudata(L, "unix{dgbound}", 1))
+    {
+        char buffer[UDP_DATAGRAMSIZE];
+        size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
+        int err;
+        p_timeout tm = &un->tm;
+        count = count < sizeof(buffer) ? count : sizeof(buffer);
+        timeout_markstart(tm);
+        err = socket_recv(&un->sock, buffer, count, &got, tm);
+        if (err != IO_DONE) {
+            lua_pushnil(L);
+            lua_pushstring(L, socket_strerror(err));
+            return 2;
+        }
+        lua_pushlstring(L, buffer, got);
+        return 1;
+    }
+    else
+        return buffer_meth_receive(L, &un->buf);
 }
 
 static int meth_getstats(lua_State *L) {
@@ -206,7 +272,7 @@
 }
 
 static int meth_bind(lua_State *L) {
-    p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
+    p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{bindable}", 1);
     const char *path =  luaL_checkstring(L, 2);
     const char *err = unix_trybind(un, path);
     if (err) {
@@ -214,6 +280,8 @@
         lua_pushstring(L, err);
         return 2;
     }
+    if (auxiliar_getclassudata(L, "unix{dgram}", 1))
+        auxiliar_setclass(L, "unix{dgbound}", 1);
     lua_pushnumber(L, 1);
     return 1;
 }
@@ -331,15 +399,16 @@
 /*-------------------------------------------------------------------------*\
 * Creates a master unix object 
 \*-------------------------------------------------------------------------*/
-static int global_create(lua_State *L) {
+static int global_create_any(lua_State *L, int dgram) {
     t_socket sock;
-    int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
+    int err;
+    err = socket_create(&sock, AF_UNIX, dgram ? SOCK_DGRAM : SOCK_STREAM, 0);
     /* try to allocate a system socket */
     if (err == IO_DONE) { 
         /* allocate unix object */
         p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
         /* set its type as master object */
-        auxiliar_setclass(L, "unix{master}", -1);
+        auxiliar_setclass(L, dgram ? "unix{dgram}" : "unix{master}", -1);
         /* initialize remaining structure fields */
         socket_setnonblocking(&sock);
         un->sock = sock;
@@ -354,3 +423,13 @@
         return 2;
     }
 }
+
+static int global_create_stream(lua_State *L)
+{
+    return global_create_any(L, 0);
+}
+
+static int global_create_dgram(lua_State *L)
+{
+    return global_create_any(L, 1);
+}
--- src/unix.h.orig	2007-10-15 06:21:05.000000000 +0200
+++ src/unix.h	2012-03-17 08:43:49.928378139 +0100
@@ -24,5 +24,6 @@
 typedef t_unix *p_unix;
 
 int luaopen_socket_unix(lua_State *L);
+int luaopen_socket_unix_dgram(lua_State *L);
 
 #endif /* UNIX_H */