]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Add socket api for lua, currently untested.
authorChris Porter <redacted>
Tue, 18 Dec 2007 16:12:03 +0000 (16:12 +0000)
committerChris Porter <redacted>
Tue, 18 Dec 2007 16:12:03 +0000 (16:12 +0000)
lua/Makefile
lua/lua.c
lua/lua.h
lua/luabot.c
lua/luasocket.c [new file with mode: 0644]
lua/luasocket.h [new file with mode: 0644]

index f4df32cdd14832cd9f7559ad35d542feea2676e7..445487a365612e02b4ba3f765da3a69b127a7ca9 100644 (file)
@@ -2,7 +2,7 @@
 .PHONY: all
 all: lua.so nterfacer_lua.so
 
-lua.so: lua.o luacommands.o luacontrol.o luabot.o lualocal.o luadebug.o luadb.o
+lua.so: lua.o luacommands.o luacontrol.o luabot.o lualocal.o luadebug.o luadb.o luasocket.o
        ld -shared -Bdynamic -o $@ $^ ${LIBLUA} ${ADDLIB}
 
 nterfacer_lua.so: nterfacer_lua.o
index 3c6220deaf3a4a02e19270cb1d2a02ae200fc68c..3535f2cbfec856f6cdd2c9114b1a65e534917862 100644 (file)
--- a/lua/lua.c
+++ b/lua/lua.c
@@ -53,6 +53,8 @@ void lua_freedebugsocket(void);
 void lua_deregisternicks(lua_list *l);
 void lua_registerlocalcommands(lua_State *ps);
 void lua_registerdebug(lua_State *ps);
+void lua_socket_closeall(lua_list *l);
+void lua_registersocketcommands(lua_State *ps);
 
 #ifdef LUA_DEBUGSOCKET
 
@@ -227,6 +229,7 @@ lua_State *lua_loadscript(char *file) {
   n->next = NULL;
   n->prev = lua_tail;
   n->nicks = NULL;
+  n->sockets = NULL;
 
   if(!lua_head) { 
     lua_head = n;
@@ -257,6 +260,7 @@ lua_State *lua_loadscript(char *file) {
 void lua_unloadscript(lua_list *l) {
   lua_onunload(l->l);
   lua_deregisternicks(l);
+  lua_socket_closeall(l);
   lua_close(l->l);
   freesstring(l->name);
 
index 6eb501e3dacc3738a595be68a3d72d737c290352..c4c0e97ff96425a9bedc3a8c0cc0639de7f84874 100644 (file)
--- a/lua/lua.h
+++ b/lua/lua.h
 #include "../lib/sstring.h"
 
 #include "lualocal.h"
+#include "luasocket.h"
 
 /*** defines ************************************/
 
-#define LUA_BOTVERSION "1.82"
+#define LUA_BOTVERSION "1.83"
 #define LUA_CHANFIXBOT "Z"
 #define LUA_OPERCHAN "#twilightzone"
 
@@ -54,6 +55,7 @@ typedef struct lua_list {
   struct lua_list *next;
   struct lua_list *prev;
   lua_localnick *nicks;
+  lua_socket *sockets;
 } lua_list;
 
 #define LUA_STARTLOOP(l) { lua_list *ll; for(ll=lua_head;ll;ll=ll->next) {  l = ll->l
index a47aa11df8f3d93ba8fdb92afd8fcc5f60aff44c..97b2413ed3c4ef9f6dd77389969e1a9a95c2acde 100644 (file)
@@ -152,6 +152,13 @@ int _lua_vpcall(lua_State *l, void *function, int mode, const char *sig, ...) {
       case 'S':
         lua_pushstring(l, ((sstring *)(va_arg(va, sstring *)))->content);
         break;
+      case 'L':
+        {
+          char *p = va_arg(va, char *);
+          long len = va_arg(va, long);
+          lua_pushlstring(l, p, len);
+        }
+        break;
       case 'N':
         {
           nick *np = va_arg(va, nick *);
diff --git a/lua/luasocket.c b/lua/luasocket.c
new file mode 100644 (file)
index 0000000..651f6e4
--- /dev/null
@@ -0,0 +1,211 @@
+/* Copyright (C) Chris Porter 2007 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include "../lib/strlfunc.h"
+#include "../core/events.h"
+
+#include "lua.h"
+#include "luabot.h"
+
+#define lua_vnpcall(F2, N2, S2, ...) _lua_vpcall(F2->l->l, (void *)F2->handler, LUA_POINTERMODE, "ls" S2 , F2->identifier, N2 , ##__VA_ARGS__)
+
+/*
+ * instead of these identifiers I could just use the file descriptor...
+ * BUT I can't remember the exact semantics of the fd table WRT reuse...
+ */
+static long nextidentifier = 0;
+void lua_socket_poll_event(int fd, short events);
+
+static int lua_socket_unix_connect(lua_State *l) {
+  int len, ret;
+  struct sockaddr_un r;
+  char *path;
+  lua_socket *ls;
+  lua_list *ll;
+
+  ll = lua_listfromstate(l);
+  if(!ll)
+    return 0;
+
+  path = (char *)lua_tostring(l, 1);
+  if(!path)
+    return 0;
+
+  ls = (lua_socket *)malloc(sizeof(lua_socket));
+  if(!ls)
+    return 0;
+
+  ls->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if(ls->fd <= -1) {
+    free(ls);
+    return 0;
+  }
+
+  memset(&r, 0, sizeof(r));
+  r.sun_family = AF_UNIX;
+  strlcpy(r.sun_path, path, sizeof(r.sun_path));
+
+  /* don't really like this, there's a macro in sys/un.h but it's not there under FreeBSD */
+  len = sizeof(r.sun_family) + strlen(r.sun_path) + 1;
+
+  /*
+   * this socket is blocking.
+   * we could potentially block the IRC socket...
+   * BUT it's far far too much work to make it writes non-blocking...
+   */
+  ret = connect(ls->fd, (struct sockaddr *)&r, len);
+  if(ret < 0) {
+    free(ls);
+    close(ls->fd);
+    return 0;
+  }
+
+  /* this whole identifier thing should probably use userdata stuff */
+  ls->identifier = nextidentifier++;
+  ls->handler = luaL_ref(l, LUA_REGISTRYINDEX);
+  ls->l = ll;
+
+  ls->next = ll->sockets;
+  ll->sockets = ls;
+
+  registerhandler(ls->fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
+
+  lua_pushlong(l, ls->identifier);
+  return 1;
+}
+
+lua_socket *socketbyfd(int fd) {
+  lua_list *l;
+  lua_socket *ls;
+
+  for(l=lua_head;l;l=l->next)
+    for(ls=l->sockets;ls;ls=ls->next)
+      if(ls->fd == fd)
+        return ls;
+
+  return NULL;
+}
+
+lua_socket *socketbyidentifier(long identifier) {
+  lua_list *l;
+  lua_socket *ls;
+
+  for(l=lua_head;l;l=l->next)
+    for(ls=l->sockets;ls;ls=ls->next)
+      if(ls->identifier == identifier)
+        return ls;
+
+  return NULL;
+}
+
+void lua_socket_call_close(lua_socket *ls) {
+  lua_socket *p, *c;
+
+  for(c=ls->l->sockets,p=NULL;c;p=c,c=c->next) {
+    if(c == ls) {
+      deregisterhandler(ls->fd, 1);
+
+      lua_vnpcall(ls, "close", "");
+
+      if(!p) {
+        ls->l->sockets = ls->next;
+      } else {
+        p->next = ls->next;
+      }
+
+      luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->handler);
+
+      free(ls);
+      return;
+    }
+  }
+
+}
+
+static int lua_socket_write(lua_State *l) {
+  char *buf;
+  long len;
+  lua_socket *ls;
+  int ret;
+
+  if(!lua_islong(l, 1))
+    LUA_RETURN(l, LUA_FAIL);
+
+  buf = (char *)lua_tostring(l, 2);
+  if(!buf)
+    LUA_RETURN(l, LUA_FAIL);
+
+  len = lua_strlen(l, 2);
+
+  ls = socketbyidentifier(lua_tolong(l, 1));
+  if(!ls)
+    LUA_RETURN(l, LUA_FAIL);
+
+  ret = write(ls->fd, buf, len);
+  if(ret != len) {
+    lua_socket_call_close(ls);
+    lua_pushint(l, -1);
+    return 1;
+  }
+
+  lua_pushint(l, 0);
+  return 1;
+}
+
+static int lua_socket_close(lua_State *l) {
+  lua_socket *ls;
+
+  if(!lua_islong(l, 1))
+    LUA_RETURN(l, LUA_FAIL);
+
+  ls = socketbyidentifier(lua_tolong(l, 1));
+  if(!ls)
+    LUA_RETURN(l, LUA_FAIL);
+
+  lua_socket_call_close(ls);
+
+  LUA_RETURN(l, LUA_OK);
+}
+
+void lua_socket_poll_event(int fd, short events) {
+  lua_socket *ls = socketbyfd(fd);
+  if(!ls)
+    return;
+
+  if(events & (POLLERR | POLLHUP)) {
+    lua_socket_call_close(ls);
+    return;
+  }
+  if(events & POLLIN) {
+    char buf[8192 * 2];
+    int bytesread;
+
+    bytesread = read(fd, buf, sizeof(buf));
+    if((bytesread == -1) && (errno == EAGAIN))
+      return;
+
+    if(bytesread <= 0) {
+      lua_socket_call_close(ls);
+      return;
+    }
+
+    lua_vnpcall(ls, "read", "L", buf, bytesread);
+  }
+}
+
+void lua_socket_closeall(lua_list *l) {
+  while(l->sockets)
+    lua_socket_call_close(l->sockets);
+}
+
+void lua_registersocketcomments(lua_State *l) {
+  lua_register(l, "socket_unix_connect", lua_socket_unix_connect);
+  lua_register(l, "socket_close", lua_socket_close);
+  lua_register(l, "socket_write", lua_socket_write);
+}
diff --git a/lua/luasocket.h b/lua/luasocket.h
new file mode 100644 (file)
index 0000000..f7669ca
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (C) Chris Porter 2007 */
+
+#ifndef _LUA_SOCKET_H
+#define _LUA_SOCKET_H
+
+#include "lua.h"
+
+typedef struct lua_socket {
+  int fd;
+  int state;
+  long handler;
+  unsigned long identifier;
+  struct lua_list *l;
+  struct lua_socket *next;
+} lua_socket;
+
+#endif
+