Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'git-sam' into diego-sam-mwild-integration

Conflicts in options.c were just due to independent small functions
being close to each other.

unix.c in mwild was broken, it wasn't using LUASOCKET_API.

serial.c needed luaL_reg renamed, and to use LUASOCKET_API.

makefile didn't respect standard DESTDIR and prefix makefile
variables, and didn't allow LUAV variable to select lua version to build
against.

I've tested the top-level install-both target builds and installs
against both lua5.1 and lua5.2, but not done further testing.

Conflicts:
	README
	config
	gem/ltn012.tex
	makefile
	src/makefile
	src/options.c
	src/options.h
	src/tcp.c
	src/usocket.c
  • Loading branch information...
commit 4b671f4551e98ac9e1d9a7407d3dffdd7eb1d3dc 2 parents f399ab2 + 195b2a7
@sam-github sam-github authored
View
3  .gitignore
@@ -0,0 +1,3 @@
+*.o
+*.so
+*.so.*
View
17 doc/reference.html
@@ -42,9 +42,9 @@
<blockquote>
<a href="dns.html">DNS (in socket)</a>
<blockquote>
-<a href="dns.html#toip">toip</a>,
+<a href="dns.html#gethostname">gethostname</a>,
<a href="dns.html#tohostname">tohostname</a>,
-<a href="dns.html#gethostname">gethostname</a>.
+<a href="dns.html#toip">toip</a>.
</blockquote>
</blockquote>
@@ -108,9 +108,9 @@
<a href="mime.html">MIME</a>
<blockquote>
<a href="mime.html#high">high-level</a>:
-<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#decode">decode</a>,
<a href="mime.html#encode">encode</a>,
+<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#stuff">stuff</a>,
<a href="mime.html#wrap">wrap</a>.
</blockquote>
@@ -120,10 +120,10 @@
<a href="mime.html#dot">dot</a>,
<a href="mime.html#eol">eol</a>,
<a href="mime.html#qp">qp</a>,
-<a href="mime.html#wrp">wrp</a>,
-<a href="mime.html#qpwrp">qpwrp</a>.
+<a href="mime.html#qpwrp">qpwrp</a>,
<a href="mime.html#unb64">unb64</a>,
<a href="mime.html#unqp">unqp</a>,
+<a href="mime.html#wrp">wrp</a>.
</blockquote>
</blockquote>
@@ -142,6 +142,8 @@
<blockquote>
<a href="socket.html">Socket</a>
<blockquote>
+<a href="socket.html#bind">bind</a>,
+<a href="socket.html#connect">connect</a>,
<a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
@@ -169,11 +171,16 @@
<a href="tcp.html#bind">bind</a>,
<a href="tcp.html#close">close</a>,
<a href="tcp.html#connect">connect</a>,
+<a href="tcp.html#dirty">dirty</a>,
+<a href="tcp.html#getfd">getfd</a>,
+<a href="tcp.html#getoption">getoption</a>,
<a href="tcp.html#getpeername">getpeername</a>,
<a href="tcp.html#getsockname">getsockname</a>,
<a href="tcp.html#getstats">getstats</a>,
+<a href="tcp.html#listen">listen</a>,
<a href="tcp.html#receive">receive</a>,
<a href="tcp.html#send">send</a>,
+<a href="tcp.html#setfd">setfd</a>,
<a href="tcp.html#setoption">setoption</a>,
<a href="tcp.html#setstats">setstats</a>,
<a href="tcp.html#settimeout">settimeout</a>,
View
4 doc/socket.html
@@ -244,6 +244,10 @@ <h2 id=socket>The socket namespace</h2>
it to <tt>select</tt>, it will be ignored.
</p>
+<p class=note>
+<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
+</p>
+
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink>
View
95 doc/tcp.html
@@ -397,7 +397,40 @@ <h2 id=tcp>TCP</h2>
</ul>
<p class=return>
-The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise.
+The method returns 1 in case of success, or <b><tt>nil</tt></b>
+followed by an error message otherwise.
+</p>
+
+<p class=note>
+Note: The descriptions above come from the man pages.
+</p>
+
+<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=getoption>
+client:<b>getoption(</b>option)</b><br>
+server:<b>getoption(</b>option)</b>
+</p>
+
+<p class=description>
+Gets options for the TCP object.
+See <a href=#setoption><tt>setoption</tt></a> for description of the
+option names and values.
+</p>
+
+<p class=parameters>
+<tt>Option</tt> is a string with the option name.
+<ul>
+
+<li> '<tt>keepalive</tt>'
+<li> '<tt>linger</tt>'
+<li> '<tt>reuseaddr</tt>'
+<li> '<tt>tcp-nodelay</tt>'
+</ul>
+
+<p class=return>
+The method returns the option <tt>value</tt> in case of success, or
+<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class=note>
@@ -508,6 +541,66 @@ <h2 id=tcp>TCP</h2>
This function returns 1.
</p>
+<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=dirty>
+master:<b>dirty()</b><br>
+client:<b>dirty()</b><br>
+server:<b>dirty()</b>
+</p>
+
+<p class=description>
+Check the read buffer status.
+</p>
+
+<p class=return>
+Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
+</p>
+
+<p class=note>
+Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+</p>
+
+<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=getfd>
+master:<b>getfd()</b><br>
+client:<b>getfd()</b><br>
+server:<b>getfd()</b>
+</p>
+
+<p class=description>
+Returns the underling socket descriptor or handle associated to the object.
+</p>
+
+<p class=return>
+The descriptor or handle. In case the object has been closed, the return will be -1.
+</p>
+
+<p class=note>
+Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+</p>
+
+<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=setfd>
+master:<b>setfd(</b>fd<b>)</b><br>
+client:<b>setfd(</b>fd<b>)</b><br>
+server:<b>setfd(</b>fd<b>)</b>
+</p>
+
+<p class=description>
+Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
+</p>
+
+<p class=return>
+No return value.
+</p>
+
+<p class=note>
+Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+</p>
+
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
View
9 gem/makefile
@@ -12,12 +12,3 @@ clean:
pdf: ltn012.pdf
open ltn012.pdf
-
-test: gem.so
-
-
-gem.o: gem.c
- gcc -c -o gem.o -Wall -ansi -W -O2 gem.c
-
-gem.so: gem.o
- export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc -bundle -undefined dynamic_lookup -o gem.so gem.o
View
15 makefile
@@ -6,10 +6,19 @@ PLATS= macosx linux win32
#
all: $(PLAT)
-$(PLATS) none install local clean:
+$(PLATS) none install install-unix local clean:
@cd src; $(MAKE) $@
-test: dummy
+test:
lua test/hello.lua
-.PHONY: dummy
+install-both:
+ touch src/*.c
+ @cd src; $(MAKE) $(PLAT) LUAV=5.1
+ @cd src; $(MAKE) install-unix LUAV=5.1
+ touch src/*.c
+ @cd src; $(MAKE) $(PLAT) LUAV=5.2
+ @cd src; $(MAKE) install-unix LUAV=5.2
+
+.PHONY: test
+
View
66 src/makefile
@@ -1,30 +1,35 @@
PLAT?=macosx
+LUAV?=5.1
+prefix=/usr/local
+#prefix=/opt/local
+#prefix=.
-INSTALL_DATA=cp
-INSTALL_EXEC=cp
-#INSTALL_TOP=/opt/local
-INSTALL_TOP=./
-
+LUAINC_macosx=/usr/local/include
#LUAINC_macosx=/opt/local/include
-LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.2.0-beta/src
+#LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.2.0-beta/src
#LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.1.4/src
-LUAINC_linux=/usr/include/lua5.1
+#LUAINC_linux=/usr/local/include/lua$(LUAV)
+LUAINC_linux=/usr/include/lua$(LUAV)
+#LUAINC_linux=/usr/local/include
+
LUAINC_win32="../../lua-5.1.3/src"
LUALIB_win32="../../lua-5.1.3"
#------
# Install directories
#
-#INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/5.1
-#INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/5.1
-INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/5.2
-INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/5.2
+
+INSTALL_DATA=cp
+INSTALL_EXEC=cp
+INSTALL_TOP=$(DESTDIR)$(prefix)
+
+INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/$(LUAV)
+INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/$(LUAV)
INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket
INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
-#INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
-INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/foo/mime
+INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
#------
@@ -78,7 +83,7 @@ LDFLAGS_win32= /nologo /link /NOLOGO /DLL /INCREMENTAL:NO \
/MANIFESTFILE:"intermediate.manifest" \
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
/SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /DYNAMICBASE:NO \
- /MACHINE:X86 ws2_32.lib lua5.1.lib /OUT:
+ /MACHINE:X86 ws2_32.lib lua$(LUAV).lib /OUT:
LD_win32=cl
SOCKET_win32=wsocket.obj
@@ -97,6 +102,7 @@ MIME_V=1.0.3
SOCKET_SO=socket.$(SO).$(SOCKET_V)
MIME_SO=mime.$(SO).$(MIME_V)
UNIX_SO=unix.$(SO)
+SERIAL_SO=serial.$(SO)
SOCKET=$(SOCKET_$(PLAT))
#------
@@ -118,7 +124,7 @@ SOCKET_OBJS= \
timeout.$(O) \
buffer.$(O) \
io.$(O) \
- auxiliar.$(O) \
+ auxiliar.$(O) \
options.$(O) \
inet.$(O) \
$(SOCKET) \
@@ -148,6 +154,19 @@ UNIX_OBJS=\
lua_typeerror.$(O)
#------
+# Modules belonging to serial (device streams)
+#
+SERIAL_OBJS:=\
+ buffer.$(O) \
+ auxiliar.$(O) \
+ options.$(O) \
+ timeout.$(O) \
+ io.$(O) \
+ usocket.$(O) \
+ serial.$(O) \
+ lua_typeerror.$(O)
+
+#------
# Files to install
#
TO_SOCKET_SHARE= \
@@ -169,13 +188,13 @@ TO_TOP_SHARE= \
default: $(PLAT)
macosx:
- $(MAKE) all PLAT=macosx
+ $(MAKE) all-unix PLAT=macosx
win32:
$(MAKE) all PLAT=win32
linux:
- $(MAKE) all PLAT=linux
+ $(MAKE) all-unix PLAT=linux
none:
@echo "Please run"
@@ -191,9 +210,14 @@ $(SOCKET_SO): $(SOCKET_OBJS)
$(MIME_SO): $(MIME_OBJS)
$(LD) $(MIME_OBJS) $(LDFLAGS)$@
+all-unix: all $(UNIX_SO) $(SERIAL_SO)
+
$(UNIX_SO): $(UNIX_OBJS)
$(LD) $(UNIX_OBJS) $(LDFLAGS)$@
+$(SERIAL_SO): $(SERIAL_OBJS)
+ $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
+
install:
mkdir -p $(INSTALL_TOP_SHARE)
$(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE)
@@ -204,12 +228,16 @@ install:
mkdir -p $(INSTALL_MIME_LIB)
$(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(SO)
+install-unix: install
+ $(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_LIB)/$(UNIX_SO)
+ $(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_LIB)/$(SERIAL_SO)
+
local:
$(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=..
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS)
- rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS)
+ rm -f $(MIME_SO) $(UNIX_SO) $(SERIAL_SO) $(MIME_OBJS) $(UNIX_OBJS)
.PHONY: all $(PLATS) default clean echo none
@@ -228,6 +256,8 @@ mime.$(O): mime.c mime.h
options.$(O): options.c auxiliar.h options.h socket.h io.h \
timeout.h usocket.h inet.h
select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
+serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
+ options.h unix.h buffer.h
tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h tcp.h buffer.h
timeout.$(O): timeout.c auxiliar.h timeout.h
View
1  src/mime.lua
@@ -11,7 +11,6 @@
local base = _G
local ltn12 = require("ltn12")
local mime = require("mime.core")
-local io = require("io")
local string = require("string")
module("mime")
View
60 src/options.c
@@ -21,6 +21,8 @@ static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name,
void *val, int len);
+static int opt_get(lua_State *L, p_socket ps, int level, int name,
+ void *val, int* len);
/*=========================================================================*\
* Exported functions
@@ -60,23 +62,43 @@ int opt_set_reuseaddr(lua_State *L, p_socket ps)
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
+int opt_get_reuseaddr(lua_State *L, p_socket ps)
+{
+ return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
+}
+
/* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
+int opt_get_reuseport(lua_State *L, p_socket ps)
+{
+ return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
+}
+
/* disables the Naggle algorithm */
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
+int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
+{
+ return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
+}
+
int opt_set_keepalive(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
+int opt_get_keepalive(lua_State *L, p_socket ps)
+{
+ return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
+}
+
int opt_set_dontroute(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
@@ -114,6 +136,21 @@ int opt_set_linger(lua_State *L, p_socket ps)
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
}
+int opt_get_linger(lua_State *L, p_socket ps)
+{
+ struct linger li; /* obj, name */
+ int len = sizeof(li);
+ int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
+ if (err)
+ return err;
+ lua_newtable(L);
+ lua_pushboolean(L, li.l_onoff);
+ lua_setfield(L, -2, "on");
+ lua_pushinteger(L, li.l_linger);
+ lua_setfield(L, -2, "timeout");
+ return 1;
+}
+
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
@@ -185,6 +222,19 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
}
static
+int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
+{
+ socklen_t socklen = *len;
+ if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, "getsockopt failed");
+ return 2;
+ }
+ *len = socklen;
+ return 0;
+}
+
+static
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
{
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
@@ -199,12 +249,10 @@ int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
- socklen_t len = sizeof(val);
- if (getsockopt(*ps, level, name, (char *) &val, &len) < 0) {
- lua_pushnil(L);
- lua_pushstring(L, "getsockopt failed");
- return 2;
- }
+ int len = sizeof(val);
+ int err = opt_get(L, ps, level, name, (char *) &val, &len);
+ if (err)
+ return err;
lua_pushboolean(L, val);
return 1;
}
View
10 src/options.h
@@ -33,14 +33,18 @@ int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
-/* invokes the appropriate option handler */
-int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
/* supported options for getoption */
+int opt_get_reuseaddr(lua_State *L, p_socket ps);
+int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
+int opt_get_keepalive(lua_State *L, p_socket ps);
+int opt_get_linger(lua_State *L, p_socket ps);
+int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
+
/* invokes the appropriate option handler */
+int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
-
#endif
View
183 src/serial.c
@@ -0,0 +1,183 @@
+/*=========================================================================*\
+* Serial stream
+* LuaSocket toolkit
+\*=========================================================================*/
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "auxiliar.h"
+#include "socket.h"
+#include "options.h"
+#include "unix.h"
+#include <sys/un.h>
+
+/*
+Reuses userdata definition from unix.h, since it is useful for all
+stream-like objects.
+
+If we stored the serial path for use in error messages or userdata
+printing, we might need our own userdata definition.
+
+Group usage is semi-inherited from unix.c, but unnecessary since we
+have only one object type.
+*/
+
+/*=========================================================================*\
+* Internal function prototypes
+\*=========================================================================*/
+static int global_create(lua_State *L);
+static int meth_send(lua_State *L);
+static int meth_receive(lua_State *L);
+static int meth_close(lua_State *L);
+static int meth_settimeout(lua_State *L);
+static int meth_getfd(lua_State *L);
+static int meth_setfd(lua_State *L);
+static int meth_dirty(lua_State *L);
+static int meth_getstats(lua_State *L);
+static int meth_setstats(lua_State *L);
+
+/* serial object methods */
+static luaL_Reg serial_methods[] = {
+ {"__gc", meth_close},
+ {"__tostring", auxiliar_tostring},
+ {"close", meth_close},
+ {"dirty", meth_dirty},
+ {"getfd", meth_getfd},
+ {"getstats", meth_getstats},
+ {"setstats", meth_setstats},
+ {"receive", meth_receive},
+ {"send", meth_send},
+ {"setfd", meth_setfd},
+ {"settimeout", meth_settimeout},
+ {NULL, NULL}
+};
+
+/* our socket creation function */
+static luaL_Reg func[] = {
+ {"serial", global_create},
+ {NULL, NULL}
+};
+
+
+/*-------------------------------------------------------------------------*\
+* Initializes module
+\*-------------------------------------------------------------------------*/
+LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
+ /* create classes */
+ auxiliar_newclass(L, "serial{client}", serial_methods);
+ /* create class groups */
+ auxiliar_add2group(L, "serial{client}", "serial{any}");
+ /* 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, "serial");
+ lua_gettable(L, -2);
+ return 1;
+}
+
+/*=========================================================================*\
+* Lua methods
+\*=========================================================================*/
+/*-------------------------------------------------------------------------*\
+* Just call buffered IO methods
+\*-------------------------------------------------------------------------*/
+static int meth_send(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
+ return buffer_meth_send(L, &un->buf);
+}
+
+static int meth_receive(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
+ return buffer_meth_receive(L, &un->buf);
+}
+
+static int meth_getstats(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
+ return buffer_meth_getstats(L, &un->buf);
+}
+
+static int meth_setstats(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
+ return buffer_meth_setstats(L, &un->buf);
+}
+
+/*-------------------------------------------------------------------------*\
+* Select support methods
+\*-------------------------------------------------------------------------*/
+static int meth_getfd(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
+ lua_pushnumber(L, (int) un->sock);
+ return 1;
+}
+
+/* this is very dangerous, but can be handy for those that are brave enough */
+static int meth_setfd(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
+ un->sock = (t_socket) luaL_checknumber(L, 2);
+ return 0;
+}
+
+static int meth_dirty(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
+ lua_pushboolean(L, !buffer_isempty(&un->buf));
+ return 1;
+}
+
+/*-------------------------------------------------------------------------*\
+* Closes socket used by object
+\*-------------------------------------------------------------------------*/
+static int meth_close(lua_State *L)
+{
+ p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
+ socket_destroy(&un->sock);
+ lua_pushnumber(L, 1);
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------*\
+* Just call tm methods
+\*-------------------------------------------------------------------------*/
+static int meth_settimeout(lua_State *L) {
+ p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
+ return timeout_meth_settimeout(L, &un->tm);
+}
+
+/*=========================================================================*\
+* Library functions
+\*=========================================================================*/
+
+
+/*-------------------------------------------------------------------------*\
+* Creates a serial object
+\*-------------------------------------------------------------------------*/
+static int global_create(lua_State *L) {
+ const char* path = luaL_checkstring(L, 1);
+
+ /* allocate unix object */
+ p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
+
+ /* open serial device */
+ t_socket sock = open(path, O_NOCTTY|O_RDWR);
+
+ /*printf("open %s on %d\n", path, sock);*/
+
+ if (sock < 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, socket_strerror(errno));
+ lua_pushnumber(L, errno);
+ return 3;
+ }
+ /* set its type as client object */
+ auxiliar_setclass(L, "serial{client}", -1);
+ /* initialize remaining structure fields */
+ socket_setnonblocking(&sock);
+ un->sock = sock;
+ io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
+ (p_error) socket_ioerror, &un->sock);
+ timeout_init(&un->tm, -1, -1);
+ buffer_init(&un->buf, &un->io, &un->tm);
+ return 1;
+}
View
3  src/socket.h
@@ -67,6 +67,9 @@ const char *socket_strerror(int err);
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
+int socket_write(p_socket ps, const char *data, size_t count,
+ size_t *sent, p_timeout tm);
+int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
const char *socket_ioerror(p_socket ps, int err);
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
View
16 src/tcp.c
@@ -33,6 +33,7 @@ static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
+static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
@@ -49,6 +50,7 @@ static luaL_Reg tcp_methods[] = {
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
+ {"getoption", meth_getoption},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
{"getstats", meth_getstats},
@@ -66,6 +68,14 @@ static luaL_Reg tcp_methods[] = {
};
/* socket option handlers */
+static t_opt optget[] = {
+ {"keepalive", opt_get_keepalive},
+ {"reuseaddr", opt_get_reuseaddr},
+ {"tcp-nodelay", opt_get_tcp_nodelay},
+ {"linger", opt_get_linger},
+ {NULL, NULL}
+};
+
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
@@ -130,6 +140,12 @@ static int meth_setstats(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
+static int meth_getoption(lua_State *L)
+{
+ p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
+ return opt_meth_getoption(L, optget, &tcp->sock);
+}
+
static int meth_setoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
View
6 src/udp.c
@@ -184,6 +184,9 @@ static int meth_receive(lua_State *L) {
count = MIN(count, sizeof(buffer));
timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm);
+ /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
+ if (err == IO_CLOSED)
+ err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
@@ -208,6 +211,9 @@ static int meth_receivefrom(lua_State *L) {
count = MIN(count, sizeof(buffer));
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
+ /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
+ if (err == IO_CLOSED)
+ err = IO_DONE;
if (err == IO_DONE) {
lua_pushlstring(L, buffer, got);
lua_pushstring(L, inet_ntoa(addr.sin_addr));
View
8 src/unix.c
@@ -39,7 +39,7 @@ static const char *unix_tryconnect(p_unix un, const char *path);
static const char *unix_trybind(p_unix un, const char *path);
/* unix object methods */
-static luaL_Reg un[] = {
+static luaL_Reg unix_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
@@ -82,9 +82,9 @@ static luaL_Reg func[] = {
\*-------------------------------------------------------------------------*/
int luaopen_socket_unix(lua_State *L) {
/* create classes */
- auxiliar_newclass(L, "unix{master}", un);
- auxiliar_newclass(L, "unix{client}", un);
- auxiliar_newclass(L, "unix{server}", un);
+ auxiliar_newclass(L, "unix{master}", unix_methods);
+ auxiliar_newclass(L, "unix{client}", unix_methods);
+ auxiliar_newclass(L, "unix{server}", unix_methods);
/* create class groups */
auxiliar_add2group(L, "unix{master}", "unix{any}");
auxiliar_add2group(L, "unix{client}", "unix{any}");
View
2  src/unix.h
@@ -21,6 +21,6 @@ typedef struct t_unix_ {
} t_unix;
typedef t_unix *p_unix;
-int luaopen_socket_unix(lua_State *L);
+LUASOCKET_API int luaopen_socket_unix(lua_State *L);
#endif /* UNIX_H */
View
76 src/usocket.c
@@ -16,7 +16,7 @@
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
-#ifdef SOCKET_POLL
+#ifndef SOCKET_SELECT
#include <sys/poll.h>
#define WAITFD_R POLLIN
@@ -49,6 +49,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
fd_set rfds, wfds, *rp, *wp;
struct timeval tv, *tp;
double t;
+ if (*ps >= FD_SETSIZE) return EINVAL;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
/* must set bits within loop, because select may have modifed them */
@@ -213,14 +214,13 @@ int socket_send(p_socket ps, const char *data, size_t count,
for ( ;; ) {
long put = (long) send(*ps, data, count, 0);
/* if we sent anything, we are done */
- if (put > 0) {
+ if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
- /* send can't really return 0, but EPIPE means the connection was
- closed */
- if (put == 0 || err == EPIPE) return IO_CLOSED;
+ /* EPIPE means the connection was closed */
+ if (err == EPIPE) return IO_CLOSED;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
@@ -243,12 +243,12 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long put = (long) sendto(*ps, data, count, 0, addr, len);
- if (put > 0) {
+ if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
- if (put == 0 || err == EPIPE) return IO_CLOSED;
+ if (err == EPIPE) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
@@ -301,6 +301,66 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
return IO_UNKNOWN;
}
+
+/*-------------------------------------------------------------------------*\
+* Write with timeout
+*
+* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
+* with send/recv replaced with write/read. We can't just use write/read
+* in the socket version, because behaviour when size is zero is different.
+\*-------------------------------------------------------------------------*/
+int socket_write(p_socket ps, const char *data, size_t count,
+ size_t *sent, p_timeout tm)
+{
+ int err;
+ *sent = 0;
+ /* avoid making system calls on closed sockets */
+ if (*ps == SOCKET_INVALID) return IO_CLOSED;
+ /* loop until we send something or we give up on error */
+ for ( ;; ) {
+ long put = (long) write(*ps, data, count);
+ /* if we sent anything, we are done */
+ if (put >= 0) {
+ *sent = put;
+ return IO_DONE;
+ }
+ err = errno;
+ /* EPIPE means the connection was closed */
+ if (err == EPIPE) return IO_CLOSED;
+ /* we call was interrupted, just try again */
+ if (err == EINTR) continue;
+ /* if failed fatal reason, report error */
+ if (err != EAGAIN) return err;
+ /* wait until we can send something or we timeout */
+ if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
+ }
+ /* can't reach here */
+ return IO_UNKNOWN;
+}
+
+/*-------------------------------------------------------------------------*\
+* Read with timeout
+* See note for socket_write
+\*-------------------------------------------------------------------------*/
+int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
+ int err;
+ *got = 0;
+ if (*ps == SOCKET_INVALID) return IO_CLOSED;
+ for ( ;; ) {
+ long taken = (long) read(*ps, data, count);
+ if (taken > 0) {
+ *got = taken;
+ return IO_DONE;
+ }
+ err = errno;
+ if (taken == 0) return IO_CLOSED;
+ if (err == EINTR) continue;
+ if (err != EAGAIN) return err;
+ if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
+ }
+ return IO_UNKNOWN;
+}
+
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
@@ -360,7 +420,7 @@ const char *socket_strerror(int err) {
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case ETIMEDOUT: return "timeout";
- default: return strerror(errno);
+ default: return strerror(err);
}
}
View
32 test/find-connect-limit
@@ -0,0 +1,32 @@
+#!/usr/bin/env lua
+--[[
+Find out how many TCP connections we can make.
+
+Use ulimit to increase the max number of descriptors:
+
+ulimit -n 10000
+ulimit -n
+
+You'll probably need to be root to do this.
+]]
+
+require "socket"
+
+host = arg[1] or "google.com"
+port = arg[2] or 80
+
+connections = {}
+
+repeat
+ c = assert(socket.connect(hostip or host, 80))
+ table.insert(connections, c)
+
+ if not hostip then
+ hostip = c:getpeername()
+ print("resolved", host, "to", hostip)
+ end
+
+ print("connection #", #connections, c, "fd", c:getfd())
+
+until false
+
View
41 test/tcp-getoptions
@@ -0,0 +1,41 @@
+#!/usr/bin/env lua
+
+require"socket"
+
+port = 8765
+
+function options(o)
+ print("options for", o)
+
+ for _, opt in ipairs{"keepalive", "reuseaddr", "tcp-nodelay"} do
+ print("getoption", opt, o:getoption(opt))
+ end
+
+ print("getoption", "linger",
+ "on", o:getoption("linger").on,
+ "timeout", o:getoption("linger").timeout)
+end
+
+local m = socket.tcp()
+
+options(m)
+
+assert(m:bind("*", port))
+assert(m:listen())
+
+options(m)
+
+m:close()
+
+local m = socket.bind("*", port)
+
+options(m)
+
+local c = socket.connect("localhost", port)
+
+options(c)
+
+local s = m:accept()
+
+options(s)
+
View
7 test/testsrvr.lua
@@ -7,7 +7,12 @@ while 1 do
print("server: waiting for client connection...");
control = assert(server:accept());
while 1 do
- command = assert(control:receive());
+ command, emsg = control:receive();
+ if emsg == "closed" then
+ control:close()
+ break
+ end
+ assert(command, emsg)
assert(control:send(ack));
print(command);
(load(command))();
View
25 test/udp-zero-length-send
@@ -0,0 +1,25 @@
+#!/usr/bin/lua
+
+--[[
+Show that luasocket returns an error message on zero-length UDP sends,
+even though the send is valid, and in fact the UDP packet is sent
+to the peer:
+
+% sudo tcpdump -i lo -n
+tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
+listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
+13:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0
+
+]]
+
+require"socket"
+
+s = assert(socket.udp())
+r = assert(socket.udp())
+assert(r:setsockname("*", 5432))
+assert(s:setpeername("127.0.0.1", 5432))
+
+ssz, emsg = s:send("")
+
+print(ssz == 0 and "OK" or "FAIL",[[send:("")]], ssz, emsg)
+
View
37 test/udp-zero-length-send-recv
@@ -0,0 +1,37 @@
+#!/usr/bin/lua
+
+--[[
+Show that luasocket returns an error message on zero-length UDP sends,
+even though the send is valid, and in fact the UDP packet is sent
+to the peer:
+
+% sudo tcpdump -i lo -n
+tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
+listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
+13:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0
+
+]]
+
+require"socket"
+
+s = assert(socket.udp())
+r = assert(socket.udp())
+assert(r:setsockname("*", 5432))
+assert(s:setpeername("127.0.0.1", 5432))
+
+ok, emsg = s:send("")
+if ok ~= 0 then
+ print("send of zero failed with:", ok, emsg)
+end
+
+assert(r:settimeout(2))
+
+ok, emsg = r:receive()
+
+if not ok or string.len(ok) ~= 0 then
+ print("fail - receive of zero failed with:", ok, emsg)
+ os.exit(1)
+end
+
+print"ok"
+
Please sign in to comment.
Something went wrong with that request. Please try again.