aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--doc/reference.html17
-rw-r--r--doc/socket.html4
-rw-r--r--doc/tcp.html95
-rw-r--r--gem/makefile9
-rw-r--r--makefile15
-rw-r--r--src/makefile66
-rw-r--r--src/mime.lua1
-rw-r--r--src/options.c60
-rw-r--r--src/options.h10
-rw-r--r--src/serial.c183
-rw-r--r--src/socket.h3
-rw-r--r--src/tcp.c16
-rw-r--r--src/udp.c6
-rw-r--r--src/unix.c8
-rw-r--r--src/unix.h2
-rw-r--r--src/usocket.c76
-rwxr-xr-xtest/find-connect-limit32
-rwxr-xr-xtest/tcp-getoptions41
-rw-r--r--test/testsrvr.lua7
-rwxr-xr-xtest/udp-zero-length-send25
-rwxr-xr-xtest/udp-zero-length-send-recv37
22 files changed, 656 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..705ce5b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
1*.o
2*.so
3*.so.*
diff --git a/doc/reference.html b/doc/reference.html
index 31f6ecf..8da3956 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -42,9 +42,9 @@ Support, Manual">
42<blockquote> 42<blockquote>
43<a href="dns.html">DNS (in socket)</a> 43<a href="dns.html">DNS (in socket)</a>
44<blockquote> 44<blockquote>
45<a href="dns.html#toip">toip</a>, 45<a href="dns.html#gethostname">gethostname</a>,
46<a href="dns.html#tohostname">tohostname</a>, 46<a href="dns.html#tohostname">tohostname</a>,
47<a href="dns.html#gethostname">gethostname</a>. 47<a href="dns.html#toip">toip</a>.
48</blockquote> 48</blockquote>
49</blockquote> 49</blockquote>
50 50
@@ -108,9 +108,9 @@ Support, Manual">
108<a href="mime.html">MIME</a> 108<a href="mime.html">MIME</a>
109<blockquote> 109<blockquote>
110<a href="mime.html#high">high-level</a>: 110<a href="mime.html#high">high-level</a>:
111<a href="mime.html#normalize">normalize</a>,
112<a href="mime.html#decode">decode</a>, 111<a href="mime.html#decode">decode</a>,
113<a href="mime.html#encode">encode</a>, 112<a href="mime.html#encode">encode</a>,
113<a href="mime.html#normalize">normalize</a>,
114<a href="mime.html#stuff">stuff</a>, 114<a href="mime.html#stuff">stuff</a>,
115<a href="mime.html#wrap">wrap</a>. 115<a href="mime.html#wrap">wrap</a>.
116</blockquote> 116</blockquote>
@@ -120,10 +120,10 @@ Support, Manual">
120<a href="mime.html#dot">dot</a>, 120<a href="mime.html#dot">dot</a>,
121<a href="mime.html#eol">eol</a>, 121<a href="mime.html#eol">eol</a>,
122<a href="mime.html#qp">qp</a>, 122<a href="mime.html#qp">qp</a>,
123<a href="mime.html#wrp">wrp</a>, 123<a href="mime.html#qpwrp">qpwrp</a>,
124<a href="mime.html#qpwrp">qpwrp</a>.
125<a href="mime.html#unb64">unb64</a>, 124<a href="mime.html#unb64">unb64</a>,
126<a href="mime.html#unqp">unqp</a>, 125<a href="mime.html#unqp">unqp</a>,
126<a href="mime.html#wrp">wrp</a>.
127</blockquote> 127</blockquote>
128</blockquote> 128</blockquote>
129 129
@@ -142,6 +142,8 @@ Support, Manual">
142<blockquote> 142<blockquote>
143<a href="socket.html">Socket</a> 143<a href="socket.html">Socket</a>
144<blockquote> 144<blockquote>
145<a href="socket.html#bind">bind</a>,
146<a href="socket.html#connect">connect</a>,
145<a href="socket.html#debug">_DEBUG</a>, 147<a href="socket.html#debug">_DEBUG</a>,
146<a href="dns.html#dns">dns</a>, 148<a href="dns.html#dns">dns</a>,
147<a href="socket.html#gettime">gettime</a>, 149<a href="socket.html#gettime">gettime</a>,
@@ -169,11 +171,16 @@ Support, Manual">
169<a href="tcp.html#bind">bind</a>, 171<a href="tcp.html#bind">bind</a>,
170<a href="tcp.html#close">close</a>, 172<a href="tcp.html#close">close</a>,
171<a href="tcp.html#connect">connect</a>, 173<a href="tcp.html#connect">connect</a>,
174<a href="tcp.html#dirty">dirty</a>,
175<a href="tcp.html#getfd">getfd</a>,
176<a href="tcp.html#getoption">getoption</a>,
172<a href="tcp.html#getpeername">getpeername</a>, 177<a href="tcp.html#getpeername">getpeername</a>,
173<a href="tcp.html#getsockname">getsockname</a>, 178<a href="tcp.html#getsockname">getsockname</a>,
174<a href="tcp.html#getstats">getstats</a>, 179<a href="tcp.html#getstats">getstats</a>,
180<a href="tcp.html#listen">listen</a>,
175<a href="tcp.html#receive">receive</a>, 181<a href="tcp.html#receive">receive</a>,
176<a href="tcp.html#send">send</a>, 182<a href="tcp.html#send">send</a>,
183<a href="tcp.html#setfd">setfd</a>,
177<a href="tcp.html#setoption">setoption</a>, 184<a href="tcp.html#setoption">setoption</a>,
178<a href="tcp.html#setstats">setstats</a>, 185<a href="tcp.html#setstats">setstats</a>,
179<a href="tcp.html#settimeout">settimeout</a>, 186<a href="tcp.html#settimeout">settimeout</a>,
diff --git a/doc/socket.html b/doc/socket.html
index 490ab50..2267b4a 100644
--- a/doc/socket.html
+++ b/doc/socket.html
@@ -244,6 +244,10 @@ method or <tt>accept</tt> might block forever.
244it to <tt>select</tt>, it will be ignored. 244it to <tt>select</tt>, it will be ignored.
245</p> 245</p>
246 246
247<p class=note>
248<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.
249</p>
250
247<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 251<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
248 252
249<p class=name id=sink> 253<p class=name id=sink>
diff --git a/doc/tcp.html b/doc/tcp.html
index d1d2154..f59d7ac 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -397,7 +397,40 @@ disables the Nagle's algorithm for the connection.
397</ul> 397</ul>
398 398
399<p class=return> 399<p class=return>
400The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise. 400The method returns 1 in case of success, or <b><tt>nil</tt></b>
401followed by an error message otherwise.
402</p>
403
404<p class=note>
405Note: The descriptions above come from the man pages.
406</p>
407
408<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
409
410<p class=name id=getoption>
411client:<b>getoption(</b>option)</b><br>
412server:<b>getoption(</b>option)</b>
413</p>
414
415<p class=description>
416Gets options for the TCP object.
417See <a href=#setoption><tt>setoption</tt></a> for description of the
418option names and values.
419</p>
420
421<p class=parameters>
422<tt>Option</tt> is a string with the option name.
423<ul>
424
425<li> '<tt>keepalive</tt>'
426<li> '<tt>linger</tt>'
427<li> '<tt>reuseaddr</tt>'
428<li> '<tt>tcp-nodelay</tt>'
429</ul>
430
431<p class=return>
432The method returns the option <tt>value</tt> in case of success, or
433<b><tt>nil</tt></b> followed by an error message otherwise.
401</p> 434</p>
402 435
403<p class=note> 436<p class=note>
@@ -508,6 +541,66 @@ This is the default mode;
508This function returns 1. 541This function returns 1.
509</p> 542</p>
510 543
544<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
545
546<p class=name id=dirty>
547master:<b>dirty()</b><br>
548client:<b>dirty()</b><br>
549server:<b>dirty()</b>
550</p>
551
552<p class=description>
553Check the read buffer status.
554</p>
555
556<p class=return>
557Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
558</p>
559
560<p class=note>
561Note: <b>This is an internal method, any use is unlikely to be portable.</b>
562</p>
563
564<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
565
566<p class=name id=getfd>
567master:<b>getfd()</b><br>
568client:<b>getfd()</b><br>
569server:<b>getfd()</b>
570</p>
571
572<p class=description>
573Returns the underling socket descriptor or handle associated to the object.
574</p>
575
576<p class=return>
577The descriptor or handle. In case the object has been closed, the return will be -1.
578</p>
579
580<p class=note>
581Note: <b>This is an internal method, any use is unlikely to be portable.</b>
582</p>
583
584<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
585
586<p class=name id=setfd>
587master:<b>setfd(</b>fd<b>)</b><br>
588client:<b>setfd(</b>fd<b>)</b><br>
589server:<b>setfd(</b>fd<b>)</b>
590</p>
591
592<p class=description>
593Sets 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.
594</p>
595
596<p class=return>
597No return value.
598</p>
599
600<p class=note>
601Note: <b>This is an internal method, any use is unlikely to be portable.</b>
602</p>
603
511<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 604<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
512 605
513<div class=footer> 606<div class=footer>
diff --git a/gem/makefile b/gem/makefile
index d2f0c93..a4287c2 100644
--- a/gem/makefile
+++ b/gem/makefile
@@ -12,12 +12,3 @@ clean:
12 12
13pdf: ltn012.pdf 13pdf: ltn012.pdf
14 open ltn012.pdf 14 open ltn012.pdf
15
16test: gem.so
17
18
19gem.o: gem.c
20 gcc -c -o gem.o -Wall -ansi -W -O2 gem.c
21
22gem.so: gem.o
23 export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc -bundle -undefined dynamic_lookup -o gem.so gem.o
diff --git a/makefile b/makefile
index 4275474..8e9e967 100644
--- a/makefile
+++ b/makefile
@@ -6,10 +6,19 @@ PLATS= macosx linux win32
6# 6#
7all: $(PLAT) 7all: $(PLAT)
8 8
9$(PLATS) none install local clean: 9$(PLATS) none install install-unix local clean:
10 @cd src; $(MAKE) $@ 10 @cd src; $(MAKE) $@
11 11
12test: dummy 12test:
13 lua test/hello.lua 13 lua test/hello.lua
14 14
15.PHONY: dummy 15install-both:
16 touch src/*.c
17 @cd src; $(MAKE) $(PLAT) LUAV=5.1
18 @cd src; $(MAKE) install-unix LUAV=5.1
19 touch src/*.c
20 @cd src; $(MAKE) $(PLAT) LUAV=5.2
21 @cd src; $(MAKE) install-unix LUAV=5.2
22
23.PHONY: test
24
diff --git a/src/makefile b/src/makefile
index b7c22da..a38ff98 100644
--- a/src/makefile
+++ b/src/makefile
@@ -1,30 +1,35 @@
1PLAT?=macosx 1PLAT?=macosx
2LUAV?=5.1
3prefix=/usr/local
4#prefix=/opt/local
5#prefix=.
2 6
3INSTALL_DATA=cp 7LUAINC_macosx=/usr/local/include
4INSTALL_EXEC=cp
5#INSTALL_TOP=/opt/local
6INSTALL_TOP=./
7
8#LUAINC_macosx=/opt/local/include 8#LUAINC_macosx=/opt/local/include
9LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.2.0-beta/src 9#LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.2.0-beta/src
10#LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.1.4/src 10#LUAINC_macosx=../../../../projects/lua_env/luaenv/lua_versions/lua-5.1.4/src
11 11
12LUAINC_linux=/usr/include/lua5.1 12#LUAINC_linux=/usr/local/include/lua$(LUAV)
13LUAINC_linux=/usr/include/lua$(LUAV)
14#LUAINC_linux=/usr/local/include
15
13LUAINC_win32="../../lua-5.1.3/src" 16LUAINC_win32="../../lua-5.1.3/src"
14LUALIB_win32="../../lua-5.1.3" 17LUALIB_win32="../../lua-5.1.3"
15 18
16#------ 19#------
17# Install directories 20# Install directories
18# 21#
19#INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/5.1 22
20#INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/5.1 23INSTALL_DATA=cp
21INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/5.2 24INSTALL_EXEC=cp
22INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/5.2 25INSTALL_TOP=$(DESTDIR)$(prefix)
26
27INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/$(LUAV)
28INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/$(LUAV)
23 29
24INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket 30INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket
25INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket 31INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
26#INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime 32INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
27INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/foo/mime
28INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime 33INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
29 34
30#------ 35#------
@@ -78,7 +83,7 @@ LDFLAGS_win32= /nologo /link /NOLOGO /DLL /INCREMENTAL:NO \
78 /MANIFESTFILE:"intermediate.manifest" \ 83 /MANIFESTFILE:"intermediate.manifest" \
79 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \ 84 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
80 /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /DYNAMICBASE:NO \ 85 /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /DYNAMICBASE:NO \
81 /MACHINE:X86 ws2_32.lib lua5.1.lib /OUT: 86 /MACHINE:X86 ws2_32.lib lua$(LUAV).lib /OUT:
82LD_win32=cl 87LD_win32=cl
83SOCKET_win32=wsocket.obj 88SOCKET_win32=wsocket.obj
84 89
@@ -97,6 +102,7 @@ MIME_V=1.0.3
97SOCKET_SO=socket.$(SO).$(SOCKET_V) 102SOCKET_SO=socket.$(SO).$(SOCKET_V)
98MIME_SO=mime.$(SO).$(MIME_V) 103MIME_SO=mime.$(SO).$(MIME_V)
99UNIX_SO=unix.$(SO) 104UNIX_SO=unix.$(SO)
105SERIAL_SO=serial.$(SO)
100SOCKET=$(SOCKET_$(PLAT)) 106SOCKET=$(SOCKET_$(PLAT))
101 107
102#------ 108#------
@@ -118,7 +124,7 @@ SOCKET_OBJS= \
118 timeout.$(O) \ 124 timeout.$(O) \
119 buffer.$(O) \ 125 buffer.$(O) \
120 io.$(O) \ 126 io.$(O) \
121 auxiliar.$(O) \ 127 auxiliar.$(O) \
122 options.$(O) \ 128 options.$(O) \
123 inet.$(O) \ 129 inet.$(O) \
124 $(SOCKET) \ 130 $(SOCKET) \
@@ -148,6 +154,19 @@ UNIX_OBJS=\
148 lua_typeerror.$(O) 154 lua_typeerror.$(O)
149 155
150#------ 156#------
157# Modules belonging to serial (device streams)
158#
159SERIAL_OBJS:=\
160 buffer.$(O) \
161 auxiliar.$(O) \
162 options.$(O) \
163 timeout.$(O) \
164 io.$(O) \
165 usocket.$(O) \
166 serial.$(O) \
167 lua_typeerror.$(O)
168
169#------
151# Files to install 170# Files to install
152# 171#
153TO_SOCKET_SHARE= \ 172TO_SOCKET_SHARE= \
@@ -169,13 +188,13 @@ TO_TOP_SHARE= \
169default: $(PLAT) 188default: $(PLAT)
170 189
171macosx: 190macosx:
172 $(MAKE) all PLAT=macosx 191 $(MAKE) all-unix PLAT=macosx
173 192
174win32: 193win32:
175 $(MAKE) all PLAT=win32 194 $(MAKE) all PLAT=win32
176 195
177linux: 196linux:
178 $(MAKE) all PLAT=linux 197 $(MAKE) all-unix PLAT=linux
179 198
180none: 199none:
181 @echo "Please run" 200 @echo "Please run"
@@ -191,9 +210,14 @@ $(SOCKET_SO): $(SOCKET_OBJS)
191$(MIME_SO): $(MIME_OBJS) 210$(MIME_SO): $(MIME_OBJS)
192 $(LD) $(MIME_OBJS) $(LDFLAGS)$@ 211 $(LD) $(MIME_OBJS) $(LDFLAGS)$@
193 212
213all-unix: all $(UNIX_SO) $(SERIAL_SO)
214
194$(UNIX_SO): $(UNIX_OBJS) 215$(UNIX_SO): $(UNIX_OBJS)
195 $(LD) $(UNIX_OBJS) $(LDFLAGS)$@ 216 $(LD) $(UNIX_OBJS) $(LDFLAGS)$@
196 217
218$(SERIAL_SO): $(SERIAL_OBJS)
219 $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
220
197install: 221install:
198 mkdir -p $(INSTALL_TOP_SHARE) 222 mkdir -p $(INSTALL_TOP_SHARE)
199 $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE) 223 $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE)
@@ -204,12 +228,16 @@ install:
204 mkdir -p $(INSTALL_MIME_LIB) 228 mkdir -p $(INSTALL_MIME_LIB)
205 $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(SO) 229 $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(SO)
206 230
231install-unix: install
232 $(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_LIB)/$(UNIX_SO)
233 $(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_LIB)/$(SERIAL_SO)
234
207local: 235local:
208 $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=.. 236 $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=..
209 237
210clean: 238clean:
211 rm -f $(SOCKET_SO) $(SOCKET_OBJS) 239 rm -f $(SOCKET_SO) $(SOCKET_OBJS)
212 rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS) 240 rm -f $(MIME_SO) $(UNIX_SO) $(SERIAL_SO) $(MIME_OBJS) $(UNIX_OBJS)
213 241
214.PHONY: all $(PLATS) default clean echo none 242.PHONY: all $(PLATS) default clean echo none
215 243
@@ -228,6 +256,8 @@ mime.$(O): mime.c mime.h
228options.$(O): options.c auxiliar.h options.h socket.h io.h \ 256options.$(O): options.c auxiliar.h options.h socket.h io.h \
229 timeout.h usocket.h inet.h 257 timeout.h usocket.h inet.h
230select.$(O): select.c socket.h io.h timeout.h usocket.h select.h 258select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
259serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
260 options.h unix.h buffer.h
231tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \ 261tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
232 inet.h options.h tcp.h buffer.h 262 inet.h options.h tcp.h buffer.h
233timeout.$(O): timeout.c auxiliar.h timeout.h 263timeout.$(O): timeout.c auxiliar.h timeout.h
diff --git a/src/mime.lua b/src/mime.lua
index 169eda2..218b38a 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -11,7 +11,6 @@
11local base = _G 11local base = _G
12local ltn12 = require("ltn12") 12local ltn12 = require("ltn12")
13local mime = require("mime.core") 13local mime = require("mime.core")
14local io = require("io")
15local string = require("string") 14local string = require("string")
16module("mime") 15module("mime")
17 16
diff --git a/src/options.c b/src/options.c
index 801adf9..ab9e621 100644
--- a/src/options.c
+++ b/src/options.c
@@ -21,6 +21,8 @@ static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
21static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); 21static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
22static int opt_set(lua_State *L, p_socket ps, int level, int name, 22static int opt_set(lua_State *L, p_socket ps, int level, int name,
23 void *val, int len); 23 void *val, int len);
24static int opt_get(lua_State *L, p_socket ps, int level, int name,
25 void *val, int* len);
24 26
25/*=========================================================================*\ 27/*=========================================================================*\
26* Exported functions 28* Exported functions
@@ -60,23 +62,43 @@ int opt_set_reuseaddr(lua_State *L, p_socket ps)
60 return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); 62 return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
61} 63}
62 64
65int opt_get_reuseaddr(lua_State *L, p_socket ps)
66{
67 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
68}
69
63/* enables reuse of local port */ 70/* enables reuse of local port */
64int opt_set_reuseport(lua_State *L, p_socket ps) 71int opt_set_reuseport(lua_State *L, p_socket ps)
65{ 72{
66 return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); 73 return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
67} 74}
68 75
76int opt_get_reuseport(lua_State *L, p_socket ps)
77{
78 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
79}
80
69/* disables the Naggle algorithm */ 81/* disables the Naggle algorithm */
70int opt_set_tcp_nodelay(lua_State *L, p_socket ps) 82int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
71{ 83{
72 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 84 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
73} 85}
74 86
87int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
88{
89 return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
90}
91
75int opt_set_keepalive(lua_State *L, p_socket ps) 92int opt_set_keepalive(lua_State *L, p_socket ps)
76{ 93{
77 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 94 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
78} 95}
79 96
97int opt_get_keepalive(lua_State *L, p_socket ps)
98{
99 return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
100}
101
80int opt_set_dontroute(lua_State *L, p_socket ps) 102int opt_set_dontroute(lua_State *L, p_socket ps)
81{ 103{
82 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); 104 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
@@ -114,6 +136,21 @@ int opt_set_linger(lua_State *L, p_socket ps)
114 return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); 136 return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
115} 137}
116 138
139int opt_get_linger(lua_State *L, p_socket ps)
140{
141 struct linger li; /* obj, name */
142 int len = sizeof(li);
143 int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
144 if (err)
145 return err;
146 lua_newtable(L);
147 lua_pushboolean(L, li.l_onoff);
148 lua_setfield(L, -2, "on");
149 lua_pushinteger(L, li.l_linger);
150 lua_setfield(L, -2, "timeout");
151 return 1;
152}
153
117int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) 154int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
118{ 155{
119 int val = (int) luaL_checknumber(L, 3); /* obj, name, int */ 156 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)
185} 222}
186 223
187static 224static
225int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
226{
227 socklen_t socklen = *len;
228 if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
229 lua_pushnil(L);
230 lua_pushstring(L, "getsockopt failed");
231 return 2;
232 }
233 *len = socklen;
234 return 0;
235}
236
237static
188int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) 238int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
189{ 239{
190 if (setsockopt(*ps, level, name, (char *) val, len) < 0) { 240 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)
199static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) 249static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
200{ 250{
201 int val = 0; 251 int val = 0;
202 socklen_t len = sizeof(val); 252 int len = sizeof(val);
203 if (getsockopt(*ps, level, name, (char *) &val, &len) < 0) { 253 int err = opt_get(L, ps, level, name, (char *) &val, &len);
204 lua_pushnil(L); 254 if (err)
205 lua_pushstring(L, "getsockopt failed"); 255 return err;
206 return 2;
207 }
208 lua_pushboolean(L, val); 256 lua_pushboolean(L, val);
209 return 1; 257 return 1;
210} 258}
diff --git a/src/options.h b/src/options.h
index 70364fc..55447f7 100644
--- a/src/options.h
+++ b/src/options.h
@@ -33,14 +33,18 @@ int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
33int opt_set_ip_add_membership(lua_State *L, p_socket ps); 33int opt_set_ip_add_membership(lua_State *L, p_socket ps);
34int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); 34int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
35int opt_set_ip6_v6only(lua_State *L, p_socket ps); 35int opt_set_ip6_v6only(lua_State *L, p_socket ps);
36/* invokes the appropriate option handler */
37int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
38 36
39/* supported options for getoption */ 37/* supported options for getoption */
38int opt_get_reuseaddr(lua_State *L, p_socket ps);
39int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
40int opt_get_keepalive(lua_State *L, p_socket ps);
41int opt_get_linger(lua_State *L, p_socket ps);
42int opt_get_reuseaddr(lua_State *L, p_socket ps);
40int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); 43int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
41int opt_get_ip_multicast_if(lua_State *L, p_socket ps); 44int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
45
42/* invokes the appropriate option handler */ 46/* invokes the appropriate option handler */
47int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
43int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); 48int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
44 49
45
46#endif 50#endif
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000..5b09e76
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,183 @@
1/*=========================================================================*\
2* Serial stream
3* LuaSocket toolkit
4\*=========================================================================*/
5#include <string.h>
6
7#include "lua.h"
8#include "lauxlib.h"
9
10#include "auxiliar.h"
11#include "socket.h"
12#include "options.h"
13#include "unix.h"
14#include <sys/un.h>
15
16/*
17Reuses userdata definition from unix.h, since it is useful for all
18stream-like objects.
19
20If we stored the serial path for use in error messages or userdata
21printing, we might need our own userdata definition.
22
23Group usage is semi-inherited from unix.c, but unnecessary since we
24have only one object type.
25*/
26
27/*=========================================================================*\
28* Internal function prototypes
29\*=========================================================================*/
30static int global_create(lua_State *L);
31static int meth_send(lua_State *L);
32static int meth_receive(lua_State *L);
33static int meth_close(lua_State *L);
34static int meth_settimeout(lua_State *L);
35static int meth_getfd(lua_State *L);
36static int meth_setfd(lua_State *L);
37static int meth_dirty(lua_State *L);
38static int meth_getstats(lua_State *L);
39static int meth_setstats(lua_State *L);
40
41/* serial object methods */
42static luaL_Reg serial_methods[] = {
43 {"__gc", meth_close},
44 {"__tostring", auxiliar_tostring},
45 {"close", meth_close},
46 {"dirty", meth_dirty},
47 {"getfd", meth_getfd},
48 {"getstats", meth_getstats},
49 {"setstats", meth_setstats},
50 {"receive", meth_receive},
51 {"send", meth_send},
52 {"setfd", meth_setfd},
53 {"settimeout", meth_settimeout},
54 {NULL, NULL}
55};
56
57/* our socket creation function */
58static luaL_Reg func[] = {
59 {"serial", global_create},
60 {NULL, NULL}
61};
62
63
64/*-------------------------------------------------------------------------*\
65* Initializes module
66\*-------------------------------------------------------------------------*/
67LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
68 /* create classes */
69 auxiliar_newclass(L, "serial{client}", serial_methods);
70 /* create class groups */
71 auxiliar_add2group(L, "serial{client}", "serial{any}");
72 /* make sure the function ends up in the package table */
73 luaL_openlib(L, "socket", func, 0);
74 /* return the function instead of the 'socket' table */
75 lua_pushstring(L, "serial");
76 lua_gettable(L, -2);
77 return 1;
78}
79
80/*=========================================================================*\
81* Lua methods
82\*=========================================================================*/
83/*-------------------------------------------------------------------------*\
84* Just call buffered IO methods
85\*-------------------------------------------------------------------------*/
86static int meth_send(lua_State *L) {
87 p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
88 return buffer_meth_send(L, &un->buf);
89}
90
91static int meth_receive(lua_State *L) {
92 p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
93 return buffer_meth_receive(L, &un->buf);
94}
95
96static int meth_getstats(lua_State *L) {
97 p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
98 return buffer_meth_getstats(L, &un->buf);
99}
100
101static int meth_setstats(lua_State *L) {
102 p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
103 return buffer_meth_setstats(L, &un->buf);
104}
105
106/*-------------------------------------------------------------------------*\
107* Select support methods
108\*-------------------------------------------------------------------------*/
109static int meth_getfd(lua_State *L) {
110 p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
111 lua_pushnumber(L, (int) un->sock);
112 return 1;
113}
114
115/* this is very dangerous, but can be handy for those that are brave enough */
116static int meth_setfd(lua_State *L) {
117 p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
118 un->sock = (t_socket) luaL_checknumber(L, 2);
119 return 0;
120}
121
122static int meth_dirty(lua_State *L) {
123 p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
124 lua_pushboolean(L, !buffer_isempty(&un->buf));
125 return 1;
126}
127
128/*-------------------------------------------------------------------------*\
129* Closes socket used by object
130\*-------------------------------------------------------------------------*/
131static int meth_close(lua_State *L)
132{
133 p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
134 socket_destroy(&un->sock);
135 lua_pushnumber(L, 1);
136 return 1;
137}
138
139
140/*-------------------------------------------------------------------------*\
141* Just call tm methods
142\*-------------------------------------------------------------------------*/
143static int meth_settimeout(lua_State *L) {
144 p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
145 return timeout_meth_settimeout(L, &un->tm);
146}
147
148/*=========================================================================*\
149* Library functions
150\*=========================================================================*/
151
152
153/*-------------------------------------------------------------------------*\
154* Creates a serial object
155\*-------------------------------------------------------------------------*/
156static int global_create(lua_State *L) {
157 const char* path = luaL_checkstring(L, 1);
158
159 /* allocate unix object */
160 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
161
162 /* open serial device */
163 t_socket sock = open(path, O_NOCTTY|O_RDWR);
164
165 /*printf("open %s on %d\n", path, sock);*/
166
167 if (sock < 0) {
168 lua_pushnil(L);
169 lua_pushstring(L, socket_strerror(errno));
170 lua_pushnumber(L, errno);
171 return 3;
172 }
173 /* set its type as client object */
174 auxiliar_setclass(L, "serial{client}", -1);
175 /* initialize remaining structure fields */
176 socket_setnonblocking(&sock);
177 un->sock = sock;
178 io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
179 (p_error) socket_ioerror, &un->sock);
180 timeout_init(&un->tm, -1, -1);
181 buffer_init(&un->buf, &un->io, &un->tm);
182 return 1;
183}
diff --git a/src/socket.h b/src/socket.h
index e325952..63573de 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -67,6 +67,9 @@ const char *socket_strerror(int err);
67int socket_send(p_socket ps, const char *data, size_t count, 67int socket_send(p_socket ps, const char *data, size_t count,
68 size_t *sent, p_timeout tm); 68 size_t *sent, p_timeout tm);
69int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 69int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
70int socket_write(p_socket ps, const char *data, size_t count,
71 size_t *sent, p_timeout tm);
72int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
70const char *socket_ioerror(p_socket ps, int err); 73const char *socket_ioerror(p_socket ps, int err);
71 74
72int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); 75int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
diff --git a/src/tcp.c b/src/tcp.c
index 19ee73c..3146467 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -33,6 +33,7 @@ static int meth_shutdown(lua_State *L);
33static int meth_receive(lua_State *L); 33static int meth_receive(lua_State *L);
34static int meth_accept(lua_State *L); 34static int meth_accept(lua_State *L);
35static int meth_close(lua_State *L); 35static int meth_close(lua_State *L);
36static int meth_getoption(lua_State *L);
36static int meth_setoption(lua_State *L); 37static int meth_setoption(lua_State *L);
37static int meth_settimeout(lua_State *L); 38static int meth_settimeout(lua_State *L);
38static int meth_getfd(lua_State *L); 39static int meth_getfd(lua_State *L);
@@ -49,6 +50,7 @@ static luaL_Reg tcp_methods[] = {
49 {"connect", meth_connect}, 50 {"connect", meth_connect},
50 {"dirty", meth_dirty}, 51 {"dirty", meth_dirty},
51 {"getfd", meth_getfd}, 52 {"getfd", meth_getfd},
53 {"getoption", meth_getoption},
52 {"getpeername", meth_getpeername}, 54 {"getpeername", meth_getpeername},
53 {"getsockname", meth_getsockname}, 55 {"getsockname", meth_getsockname},
54 {"getstats", meth_getstats}, 56 {"getstats", meth_getstats},
@@ -66,6 +68,14 @@ static luaL_Reg tcp_methods[] = {
66}; 68};
67 69
68/* socket option handlers */ 70/* socket option handlers */
71static t_opt optget[] = {
72 {"keepalive", opt_get_keepalive},
73 {"reuseaddr", opt_get_reuseaddr},
74 {"tcp-nodelay", opt_get_tcp_nodelay},
75 {"linger", opt_get_linger},
76 {NULL, NULL}
77};
78
69static t_opt optset[] = { 79static t_opt optset[] = {
70 {"keepalive", opt_set_keepalive}, 80 {"keepalive", opt_set_keepalive},
71 {"reuseaddr", opt_set_reuseaddr}, 81 {"reuseaddr", opt_set_reuseaddr},
@@ -130,6 +140,12 @@ static int meth_setstats(lua_State *L) {
130/*-------------------------------------------------------------------------*\ 140/*-------------------------------------------------------------------------*\
131* Just call option handler 141* Just call option handler
132\*-------------------------------------------------------------------------*/ 142\*-------------------------------------------------------------------------*/
143static int meth_getoption(lua_State *L)
144{
145 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
146 return opt_meth_getoption(L, optget, &tcp->sock);
147}
148
133static int meth_setoption(lua_State *L) 149static int meth_setoption(lua_State *L)
134{ 150{
135 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); 151 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
diff --git a/src/udp.c b/src/udp.c
index 13007fb..386051a 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -184,6 +184,9 @@ static int meth_receive(lua_State *L) {
184 count = MIN(count, sizeof(buffer)); 184 count = MIN(count, sizeof(buffer));
185 timeout_markstart(tm); 185 timeout_markstart(tm);
186 err = socket_recv(&udp->sock, buffer, count, &got, tm); 186 err = socket_recv(&udp->sock, buffer, count, &got, tm);
187 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
188 if (err == IO_CLOSED)
189 err = IO_DONE;
187 if (err != IO_DONE) { 190 if (err != IO_DONE) {
188 lua_pushnil(L); 191 lua_pushnil(L);
189 lua_pushstring(L, udp_strerror(err)); 192 lua_pushstring(L, udp_strerror(err));
@@ -208,6 +211,9 @@ static int meth_receivefrom(lua_State *L) {
208 count = MIN(count, sizeof(buffer)); 211 count = MIN(count, sizeof(buffer));
209 err = socket_recvfrom(&udp->sock, buffer, count, &got, 212 err = socket_recvfrom(&udp->sock, buffer, count, &got,
210 (SA *) &addr, &addr_len, tm); 213 (SA *) &addr, &addr_len, tm);
214 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
215 if (err == IO_CLOSED)
216 err = IO_DONE;
211 if (err == IO_DONE) { 217 if (err == IO_DONE) {
212 lua_pushlstring(L, buffer, got); 218 lua_pushlstring(L, buffer, got);
213 lua_pushstring(L, inet_ntoa(addr.sin_addr)); 219 lua_pushstring(L, inet_ntoa(addr.sin_addr));
diff --git a/src/unix.c b/src/unix.c
index b08d325..935d4c3 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -39,7 +39,7 @@ static const char *unix_tryconnect(p_unix un, const char *path);
39static const char *unix_trybind(p_unix un, const char *path); 39static const char *unix_trybind(p_unix un, const char *path);
40 40
41/* unix object methods */ 41/* unix object methods */
42static luaL_Reg un[] = { 42static luaL_Reg unix_methods[] = {
43 {"__gc", meth_close}, 43 {"__gc", meth_close},
44 {"__tostring", auxiliar_tostring}, 44 {"__tostring", auxiliar_tostring},
45 {"accept", meth_accept}, 45 {"accept", meth_accept},
@@ -82,9 +82,9 @@ static luaL_Reg func[] = {
82\*-------------------------------------------------------------------------*/ 82\*-------------------------------------------------------------------------*/
83int luaopen_socket_unix(lua_State *L) { 83int luaopen_socket_unix(lua_State *L) {
84 /* create classes */ 84 /* create classes */
85 auxiliar_newclass(L, "unix{master}", un); 85 auxiliar_newclass(L, "unix{master}", unix_methods);
86 auxiliar_newclass(L, "unix{client}", un); 86 auxiliar_newclass(L, "unix{client}", unix_methods);
87 auxiliar_newclass(L, "unix{server}", un); 87 auxiliar_newclass(L, "unix{server}", unix_methods);
88 /* create class groups */ 88 /* create class groups */
89 auxiliar_add2group(L, "unix{master}", "unix{any}"); 89 auxiliar_add2group(L, "unix{master}", "unix{any}");
90 auxiliar_add2group(L, "unix{client}", "unix{any}"); 90 auxiliar_add2group(L, "unix{client}", "unix{any}");
diff --git a/src/unix.h b/src/unix.h
index 39fa719..3a7e1e6 100644
--- a/src/unix.h
+++ b/src/unix.h
@@ -21,6 +21,6 @@ typedef struct t_unix_ {
21} t_unix; 21} t_unix;
22typedef t_unix *p_unix; 22typedef t_unix *p_unix;
23 23
24int luaopen_socket_unix(lua_State *L); 24LUASOCKET_API int luaopen_socket_unix(lua_State *L);
25 25
26#endif /* UNIX_H */ 26#endif /* UNIX_H */
diff --git a/src/usocket.c b/src/usocket.c
index fdab123..bf2d19c 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -16,7 +16,7 @@
16/*-------------------------------------------------------------------------*\ 16/*-------------------------------------------------------------------------*\
17* Wait for readable/writable/connected socket with timeout 17* Wait for readable/writable/connected socket with timeout
18\*-------------------------------------------------------------------------*/ 18\*-------------------------------------------------------------------------*/
19#ifdef SOCKET_POLL 19#ifndef SOCKET_SELECT
20#include <sys/poll.h> 20#include <sys/poll.h>
21 21
22#define WAITFD_R POLLIN 22#define WAITFD_R POLLIN
@@ -49,6 +49,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
49 fd_set rfds, wfds, *rp, *wp; 49 fd_set rfds, wfds, *rp, *wp;
50 struct timeval tv, *tp; 50 struct timeval tv, *tp;
51 double t; 51 double t;
52 if (*ps >= FD_SETSIZE) return EINVAL;
52 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ 53 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
53 do { 54 do {
54 /* must set bits within loop, because select may have modifed them */ 55 /* 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,
213 for ( ;; ) { 214 for ( ;; ) {
214 long put = (long) send(*ps, data, count, 0); 215 long put = (long) send(*ps, data, count, 0);
215 /* if we sent anything, we are done */ 216 /* if we sent anything, we are done */
216 if (put > 0) { 217 if (put >= 0) {
217 *sent = put; 218 *sent = put;
218 return IO_DONE; 219 return IO_DONE;
219 } 220 }
220 err = errno; 221 err = errno;
221 /* send can't really return 0, but EPIPE means the connection was 222 /* EPIPE means the connection was closed */
222 closed */ 223 if (err == EPIPE) return IO_CLOSED;
223 if (put == 0 || err == EPIPE) return IO_CLOSED;
224 /* we call was interrupted, just try again */ 224 /* we call was interrupted, just try again */
225 if (err == EINTR) continue; 225 if (err == EINTR) continue;
226 /* if failed fatal reason, report error */ 226 /* 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,
243 if (*ps == SOCKET_INVALID) return IO_CLOSED; 243 if (*ps == SOCKET_INVALID) return IO_CLOSED;
244 for ( ;; ) { 244 for ( ;; ) {
245 long put = (long) sendto(*ps, data, count, 0, addr, len); 245 long put = (long) sendto(*ps, data, count, 0, addr, len);
246 if (put > 0) { 246 if (put >= 0) {
247 *sent = put; 247 *sent = put;
248 return IO_DONE; 248 return IO_DONE;
249 } 249 }
250 err = errno; 250 err = errno;
251 if (put == 0 || err == EPIPE) return IO_CLOSED; 251 if (err == EPIPE) return IO_CLOSED;
252 if (err == EINTR) continue; 252 if (err == EINTR) continue;
253 if (err != EAGAIN) return err; 253 if (err != EAGAIN) return err;
254 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; 254 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,
301 return IO_UNKNOWN; 301 return IO_UNKNOWN;
302} 302}
303 303
304
305/*-------------------------------------------------------------------------*\
306* Write with timeout
307*
308* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
309* with send/recv replaced with write/read. We can't just use write/read
310* in the socket version, because behaviour when size is zero is different.
311\*-------------------------------------------------------------------------*/
312int socket_write(p_socket ps, const char *data, size_t count,
313 size_t *sent, p_timeout tm)
314{
315 int err;
316 *sent = 0;
317 /* avoid making system calls on closed sockets */
318 if (*ps == SOCKET_INVALID) return IO_CLOSED;
319 /* loop until we send something or we give up on error */
320 for ( ;; ) {
321 long put = (long) write(*ps, data, count);
322 /* if we sent anything, we are done */
323 if (put >= 0) {
324 *sent = put;
325 return IO_DONE;
326 }
327 err = errno;
328 /* EPIPE means the connection was closed */
329 if (err == EPIPE) return IO_CLOSED;
330 /* we call was interrupted, just try again */
331 if (err == EINTR) continue;
332 /* if failed fatal reason, report error */
333 if (err != EAGAIN) return err;
334 /* wait until we can send something or we timeout */
335 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
336 }
337 /* can't reach here */
338 return IO_UNKNOWN;
339}
340
341/*-------------------------------------------------------------------------*\
342* Read with timeout
343* See note for socket_write
344\*-------------------------------------------------------------------------*/
345int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
346 int err;
347 *got = 0;
348 if (*ps == SOCKET_INVALID) return IO_CLOSED;
349 for ( ;; ) {
350 long taken = (long) read(*ps, data, count);
351 if (taken > 0) {
352 *got = taken;
353 return IO_DONE;
354 }
355 err = errno;
356 if (taken == 0) return IO_CLOSED;
357 if (err == EINTR) continue;
358 if (err != EAGAIN) return err;
359 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
360 }
361 return IO_UNKNOWN;
362}
363
304/*-------------------------------------------------------------------------*\ 364/*-------------------------------------------------------------------------*\
305* Put socket into blocking mode 365* Put socket into blocking mode
306\*-------------------------------------------------------------------------*/ 366\*-------------------------------------------------------------------------*/
@@ -360,7 +420,7 @@ const char *socket_strerror(int err) {
360 case ECONNABORTED: return "closed"; 420 case ECONNABORTED: return "closed";
361 case ECONNRESET: return "closed"; 421 case ECONNRESET: return "closed";
362 case ETIMEDOUT: return "timeout"; 422 case ETIMEDOUT: return "timeout";
363 default: return strerror(errno); 423 default: return strerror(err);
364 } 424 }
365} 425}
366 426
diff --git a/test/find-connect-limit b/test/find-connect-limit
new file mode 100755
index 0000000..ad0c3f5
--- /dev/null
+++ b/test/find-connect-limit
@@ -0,0 +1,32 @@
1#!/usr/bin/env lua
2--[[
3Find out how many TCP connections we can make.
4
5Use ulimit to increase the max number of descriptors:
6
7ulimit -n 10000
8ulimit -n
9
10You'll probably need to be root to do this.
11]]
12
13require "socket"
14
15host = arg[1] or "google.com"
16port = arg[2] or 80
17
18connections = {}
19
20repeat
21 c = assert(socket.connect(hostip or host, 80))
22 table.insert(connections, c)
23
24 if not hostip then
25 hostip = c:getpeername()
26 print("resolved", host, "to", hostip)
27 end
28
29 print("connection #", #connections, c, "fd", c:getfd())
30
31until false
32
diff --git a/test/tcp-getoptions b/test/tcp-getoptions
new file mode 100755
index 0000000..f9b3d1b
--- /dev/null
+++ b/test/tcp-getoptions
@@ -0,0 +1,41 @@
1#!/usr/bin/env lua
2
3require"socket"
4
5port = 8765
6
7function options(o)
8 print("options for", o)
9
10 for _, opt in ipairs{"keepalive", "reuseaddr", "tcp-nodelay"} do
11 print("getoption", opt, o:getoption(opt))
12 end
13
14 print("getoption", "linger",
15 "on", o:getoption("linger").on,
16 "timeout", o:getoption("linger").timeout)
17end
18
19local m = socket.tcp()
20
21options(m)
22
23assert(m:bind("*", port))
24assert(m:listen())
25
26options(m)
27
28m:close()
29
30local m = socket.bind("*", port)
31
32options(m)
33
34local c = socket.connect("localhost", port)
35
36options(c)
37
38local s = m:accept()
39
40options(s)
41
diff --git a/test/testsrvr.lua b/test/testsrvr.lua
index 7ddff6e..ff31442 100644
--- a/test/testsrvr.lua
+++ b/test/testsrvr.lua
@@ -7,7 +7,12 @@ while 1 do
7 print("server: waiting for client connection..."); 7 print("server: waiting for client connection...");
8 control = assert(server:accept()); 8 control = assert(server:accept());
9 while 1 do 9 while 1 do
10 command = assert(control:receive()); 10 command, emsg = control:receive();
11 if emsg == "closed" then
12 control:close()
13 break
14 end
15 assert(command, emsg)
11 assert(control:send(ack)); 16 assert(control:send(ack));
12 print(command); 17 print(command);
13 (load(command))(); 18 (load(command))();
diff --git a/test/udp-zero-length-send b/test/udp-zero-length-send
new file mode 100755
index 0000000..a594944
--- /dev/null
+++ b/test/udp-zero-length-send
@@ -0,0 +1,25 @@
1#!/usr/bin/lua
2
3--[[
4Show that luasocket returns an error message on zero-length UDP sends,
5even though the send is valid, and in fact the UDP packet is sent
6to the peer:
7
8% sudo tcpdump -i lo -n
9tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
10listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
1113:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0
12
13]]
14
15require"socket"
16
17s = assert(socket.udp())
18r = assert(socket.udp())
19assert(r:setsockname("*", 5432))
20assert(s:setpeername("127.0.0.1", 5432))
21
22ssz, emsg = s:send("")
23
24print(ssz == 0 and "OK" or "FAIL",[[send:("")]], ssz, emsg)
25
diff --git a/test/udp-zero-length-send-recv b/test/udp-zero-length-send-recv
new file mode 100755
index 0000000..541efd4
--- /dev/null
+++ b/test/udp-zero-length-send-recv
@@ -0,0 +1,37 @@
1#!/usr/bin/lua
2
3--[[
4Show that luasocket returns an error message on zero-length UDP sends,
5even though the send is valid, and in fact the UDP packet is sent
6to the peer:
7
8% sudo tcpdump -i lo -n
9tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
10listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
1113:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0
12
13]]
14
15require"socket"
16
17s = assert(socket.udp())
18r = assert(socket.udp())
19assert(r:setsockname("*", 5432))
20assert(s:setpeername("127.0.0.1", 5432))
21
22ok, emsg = s:send("")
23if ok ~= 0 then
24 print("send of zero failed with:", ok, emsg)
25end
26
27assert(r:settimeout(2))
28
29ok, emsg = r:receive()
30
31if not ok or string.len(ok) ~= 0 then
32 print("fail - receive of zero failed with:", ok, emsg)
33 os.exit(1)
34end
35
36print"ok"
37