diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | doc/reference.html | 17 | ||||
-rw-r--r-- | doc/socket.html | 4 | ||||
-rw-r--r-- | doc/tcp.html | 95 | ||||
-rw-r--r-- | gem/makefile | 9 | ||||
-rw-r--r-- | makefile | 15 | ||||
-rw-r--r-- | src/makefile | 66 | ||||
-rw-r--r-- | src/mime.lua | 1 | ||||
-rw-r--r-- | src/options.c | 60 | ||||
-rw-r--r-- | src/options.h | 10 | ||||
-rw-r--r-- | src/serial.c | 183 | ||||
-rw-r--r-- | src/socket.h | 3 | ||||
-rw-r--r-- | src/tcp.c | 16 | ||||
-rw-r--r-- | src/udp.c | 6 | ||||
-rw-r--r-- | src/unix.c | 8 | ||||
-rw-r--r-- | src/unix.h | 2 | ||||
-rw-r--r-- | src/usocket.c | 76 | ||||
-rwxr-xr-x | test/find-connect-limit | 32 | ||||
-rwxr-xr-x | test/tcp-getoptions | 41 | ||||
-rw-r--r-- | test/testsrvr.lua | 7 | ||||
-rwxr-xr-x | test/udp-zero-length-send | 25 | ||||
-rwxr-xr-x | test/udp-zero-length-send-recv | 37 |
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. | |||
244 | it to <tt>select</tt>, it will be ignored. | 244 | it 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> |
400 | The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise. | 400 | The method returns 1 in case of success, or <b><tt>nil</tt></b> |
401 | followed by an error message otherwise. | ||
402 | </p> | ||
403 | |||
404 | <p class=note> | ||
405 | Note: The descriptions above come from the man pages. | ||
406 | </p> | ||
407 | |||
408 | <!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
409 | |||
410 | <p class=name id=getoption> | ||
411 | client:<b>getoption(</b>option)</b><br> | ||
412 | server:<b>getoption(</b>option)</b> | ||
413 | </p> | ||
414 | |||
415 | <p class=description> | ||
416 | Gets options for the TCP object. | ||
417 | See <a href=#setoption><tt>setoption</tt></a> for description of the | ||
418 | option 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> | ||
432 | The 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; | |||
508 | This function returns 1. | 541 | This function returns 1. |
509 | </p> | 542 | </p> |
510 | 543 | ||
544 | <!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
545 | |||
546 | <p class=name id=dirty> | ||
547 | master:<b>dirty()</b><br> | ||
548 | client:<b>dirty()</b><br> | ||
549 | server:<b>dirty()</b> | ||
550 | </p> | ||
551 | |||
552 | <p class=description> | ||
553 | Check the read buffer status. | ||
554 | </p> | ||
555 | |||
556 | <p class=return> | ||
557 | Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise. | ||
558 | </p> | ||
559 | |||
560 | <p class=note> | ||
561 | Note: <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> | ||
567 | master:<b>getfd()</b><br> | ||
568 | client:<b>getfd()</b><br> | ||
569 | server:<b>getfd()</b> | ||
570 | </p> | ||
571 | |||
572 | <p class=description> | ||
573 | Returns the underling socket descriptor or handle associated to the object. | ||
574 | </p> | ||
575 | |||
576 | <p class=return> | ||
577 | The descriptor or handle. In case the object has been closed, the return will be -1. | ||
578 | </p> | ||
579 | |||
580 | <p class=note> | ||
581 | Note: <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> | ||
587 | master:<b>setfd(</b>fd<b>)</b><br> | ||
588 | client:<b>setfd(</b>fd<b>)</b><br> | ||
589 | server:<b>setfd(</b>fd<b>)</b> | ||
590 | </p> | ||
591 | |||
592 | <p class=description> | ||
593 | 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. | ||
594 | </p> | ||
595 | |||
596 | <p class=return> | ||
597 | No return value. | ||
598 | </p> | ||
599 | |||
600 | <p class=note> | ||
601 | Note: <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 | ||
13 | pdf: ltn012.pdf | 13 | pdf: ltn012.pdf |
14 | open ltn012.pdf | 14 | open ltn012.pdf |
15 | |||
16 | test: gem.so | ||
17 | |||
18 | |||
19 | gem.o: gem.c | ||
20 | gcc -c -o gem.o -Wall -ansi -W -O2 gem.c | ||
21 | |||
22 | gem.so: gem.o | ||
23 | export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc -bundle -undefined dynamic_lookup -o gem.so gem.o | ||
@@ -6,10 +6,19 @@ PLATS= macosx linux win32 | |||
6 | # | 6 | # |
7 | all: $(PLAT) | 7 | all: $(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 | ||
12 | test: dummy | 12 | test: |
13 | lua test/hello.lua | 13 | lua test/hello.lua |
14 | 14 | ||
15 | .PHONY: dummy | 15 | install-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 @@ | |||
1 | PLAT?=macosx | 1 | PLAT?=macosx |
2 | LUAV?=5.1 | ||
3 | prefix=/usr/local | ||
4 | #prefix=/opt/local | ||
5 | #prefix=. | ||
2 | 6 | ||
3 | INSTALL_DATA=cp | 7 | LUAINC_macosx=/usr/local/include |
4 | INSTALL_EXEC=cp | ||
5 | #INSTALL_TOP=/opt/local | ||
6 | INSTALL_TOP=./ | ||
7 | |||
8 | #LUAINC_macosx=/opt/local/include | 8 | #LUAINC_macosx=/opt/local/include |
9 | LUAINC_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 | ||
12 | LUAINC_linux=/usr/include/lua5.1 | 12 | #LUAINC_linux=/usr/local/include/lua$(LUAV) |
13 | LUAINC_linux=/usr/include/lua$(LUAV) | ||
14 | #LUAINC_linux=/usr/local/include | ||
15 | |||
13 | LUAINC_win32="../../lua-5.1.3/src" | 16 | LUAINC_win32="../../lua-5.1.3/src" |
14 | LUALIB_win32="../../lua-5.1.3" | 17 | LUALIB_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 | 23 | INSTALL_DATA=cp |
21 | INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/5.2 | 24 | INSTALL_EXEC=cp |
22 | INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/5.2 | 25 | INSTALL_TOP=$(DESTDIR)$(prefix) |
26 | |||
27 | INSTALL_TOP_SHARE=$(INSTALL_TOP)/share/lua/$(LUAV) | ||
28 | INSTALL_TOP_LIB=$(INSTALL_TOP)/lib/lua/$(LUAV) | ||
23 | 29 | ||
24 | INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket | 30 | INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket |
25 | INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket | 31 | INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket |
26 | #INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime | 32 | INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime |
27 | INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/foo/mime | ||
28 | INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime | 33 | INSTALL_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: |
82 | LD_win32=cl | 87 | LD_win32=cl |
83 | SOCKET_win32=wsocket.obj | 88 | SOCKET_win32=wsocket.obj |
84 | 89 | ||
@@ -97,6 +102,7 @@ MIME_V=1.0.3 | |||
97 | SOCKET_SO=socket.$(SO).$(SOCKET_V) | 102 | SOCKET_SO=socket.$(SO).$(SOCKET_V) |
98 | MIME_SO=mime.$(SO).$(MIME_V) | 103 | MIME_SO=mime.$(SO).$(MIME_V) |
99 | UNIX_SO=unix.$(SO) | 104 | UNIX_SO=unix.$(SO) |
105 | SERIAL_SO=serial.$(SO) | ||
100 | SOCKET=$(SOCKET_$(PLAT)) | 106 | SOCKET=$(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 | # | ||
159 | SERIAL_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 | # |
153 | TO_SOCKET_SHARE= \ | 172 | TO_SOCKET_SHARE= \ |
@@ -169,13 +188,13 @@ TO_TOP_SHARE= \ | |||
169 | default: $(PLAT) | 188 | default: $(PLAT) |
170 | 189 | ||
171 | macosx: | 190 | macosx: |
172 | $(MAKE) all PLAT=macosx | 191 | $(MAKE) all-unix PLAT=macosx |
173 | 192 | ||
174 | win32: | 193 | win32: |
175 | $(MAKE) all PLAT=win32 | 194 | $(MAKE) all PLAT=win32 |
176 | 195 | ||
177 | linux: | 196 | linux: |
178 | $(MAKE) all PLAT=linux | 197 | $(MAKE) all-unix PLAT=linux |
179 | 198 | ||
180 | none: | 199 | none: |
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 | ||
213 | all-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 | |||
197 | install: | 221 | install: |
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 | ||
231 | install-unix: install | ||
232 | $(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_LIB)/$(UNIX_SO) | ||
233 | $(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_LIB)/$(SERIAL_SO) | ||
234 | |||
207 | local: | 235 | local: |
208 | $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=.. | 236 | $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=.. |
209 | 237 | ||
210 | clean: | 238 | clean: |
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 | |||
228 | options.$(O): options.c auxiliar.h options.h socket.h io.h \ | 256 | options.$(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 |
230 | select.$(O): select.c socket.h io.h timeout.h usocket.h select.h | 258 | select.$(O): select.c socket.h io.h timeout.h usocket.h select.h |
259 | serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \ | ||
260 | options.h unix.h buffer.h | ||
231 | tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \ | 261 | tcp.$(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 |
233 | timeout.$(O): timeout.c auxiliar.h timeout.h | 263 | timeout.$(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 @@ | |||
11 | local base = _G | 11 | local base = _G |
12 | local ltn12 = require("ltn12") | 12 | local ltn12 = require("ltn12") |
13 | local mime = require("mime.core") | 13 | local mime = require("mime.core") |
14 | local io = require("io") | ||
15 | local string = require("string") | 14 | local string = require("string") |
16 | module("mime") | 15 | module("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); | |||
21 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); | 21 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); |
22 | static int opt_set(lua_State *L, p_socket ps, int level, int name, | 22 | static int opt_set(lua_State *L, p_socket ps, int level, int name, |
23 | void *val, int len); | 23 | void *val, int len); |
24 | static 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 | ||
65 | int 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 */ |
64 | int opt_set_reuseport(lua_State *L, p_socket ps) | 71 | int 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 | ||
76 | int 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 */ |
70 | int opt_set_tcp_nodelay(lua_State *L, p_socket ps) | 82 | int 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 | ||
87 | int opt_get_tcp_nodelay(lua_State *L, p_socket ps) | ||
88 | { | ||
89 | return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); | ||
90 | } | ||
91 | |||
75 | int opt_set_keepalive(lua_State *L, p_socket ps) | 92 | int 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 | ||
97 | int opt_get_keepalive(lua_State *L, p_socket ps) | ||
98 | { | ||
99 | return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); | ||
100 | } | ||
101 | |||
80 | int opt_set_dontroute(lua_State *L, p_socket ps) | 102 | int 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 | ||
139 | int 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 | |||
117 | int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) | 154 | int 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 | ||
187 | static | 224 | static |
225 | int 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 | |||
237 | static | ||
188 | int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) | 238 | int 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) | |||
199 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) | 249 | static 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); | |||
33 | int opt_set_ip_add_membership(lua_State *L, p_socket ps); | 33 | int opt_set_ip_add_membership(lua_State *L, p_socket ps); |
34 | int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); | 34 | int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); |
35 | int opt_set_ip6_v6only(lua_State *L, p_socket ps); | 35 | int opt_set_ip6_v6only(lua_State *L, p_socket ps); |
36 | /* invokes the appropriate option handler */ | ||
37 | int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); | ||
38 | 36 | ||
39 | /* supported options for getoption */ | 37 | /* supported options for getoption */ |
38 | int opt_get_reuseaddr(lua_State *L, p_socket ps); | ||
39 | int opt_get_tcp_nodelay(lua_State *L, p_socket ps); | ||
40 | int opt_get_keepalive(lua_State *L, p_socket ps); | ||
41 | int opt_get_linger(lua_State *L, p_socket ps); | ||
42 | int opt_get_reuseaddr(lua_State *L, p_socket ps); | ||
40 | int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); | 43 | int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); |
41 | int opt_get_ip_multicast_if(lua_State *L, p_socket ps); | 44 | int opt_get_ip_multicast_if(lua_State *L, p_socket ps); |
45 | |||
42 | /* invokes the appropriate option handler */ | 46 | /* invokes the appropriate option handler */ |
47 | int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); | ||
43 | int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); | 48 | int 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 | /* | ||
17 | Reuses userdata definition from unix.h, since it is useful for all | ||
18 | stream-like objects. | ||
19 | |||
20 | If we stored the serial path for use in error messages or userdata | ||
21 | printing, we might need our own userdata definition. | ||
22 | |||
23 | Group usage is semi-inherited from unix.c, but unnecessary since we | ||
24 | have only one object type. | ||
25 | */ | ||
26 | |||
27 | /*=========================================================================*\ | ||
28 | * Internal function prototypes | ||
29 | \*=========================================================================*/ | ||
30 | static int global_create(lua_State *L); | ||
31 | static int meth_send(lua_State *L); | ||
32 | static int meth_receive(lua_State *L); | ||
33 | static int meth_close(lua_State *L); | ||
34 | static int meth_settimeout(lua_State *L); | ||
35 | static int meth_getfd(lua_State *L); | ||
36 | static int meth_setfd(lua_State *L); | ||
37 | static int meth_dirty(lua_State *L); | ||
38 | static int meth_getstats(lua_State *L); | ||
39 | static int meth_setstats(lua_State *L); | ||
40 | |||
41 | /* serial object methods */ | ||
42 | static 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 */ | ||
58 | static luaL_Reg func[] = { | ||
59 | {"serial", global_create}, | ||
60 | {NULL, NULL} | ||
61 | }; | ||
62 | |||
63 | |||
64 | /*-------------------------------------------------------------------------*\ | ||
65 | * Initializes module | ||
66 | \*-------------------------------------------------------------------------*/ | ||
67 | LUASOCKET_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 | \*-------------------------------------------------------------------------*/ | ||
86 | static 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 | |||
91 | static 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 | |||
96 | static 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 | |||
101 | static 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 | \*-------------------------------------------------------------------------*/ | ||
109 | static 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 */ | ||
116 | static 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 | |||
122 | static 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 | \*-------------------------------------------------------------------------*/ | ||
131 | static 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 | \*-------------------------------------------------------------------------*/ | ||
143 | static 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 | \*-------------------------------------------------------------------------*/ | ||
156 | static 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); | |||
67 | int socket_send(p_socket ps, const char *data, size_t count, | 67 | int 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); |
69 | int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); | 69 | int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); |
70 | int socket_write(p_socket ps, const char *data, size_t count, | ||
71 | size_t *sent, p_timeout tm); | ||
72 | int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); | ||
70 | const char *socket_ioerror(p_socket ps, int err); | 73 | const char *socket_ioerror(p_socket ps, int err); |
71 | 74 | ||
72 | int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); | 75 | int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); |
@@ -33,6 +33,7 @@ static int meth_shutdown(lua_State *L); | |||
33 | static int meth_receive(lua_State *L); | 33 | static int meth_receive(lua_State *L); |
34 | static int meth_accept(lua_State *L); | 34 | static int meth_accept(lua_State *L); |
35 | static int meth_close(lua_State *L); | 35 | static int meth_close(lua_State *L); |
36 | static int meth_getoption(lua_State *L); | ||
36 | static int meth_setoption(lua_State *L); | 37 | static int meth_setoption(lua_State *L); |
37 | static int meth_settimeout(lua_State *L); | 38 | static int meth_settimeout(lua_State *L); |
38 | static int meth_getfd(lua_State *L); | 39 | static 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 */ |
71 | static 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 | |||
69 | static t_opt optset[] = { | 79 | static 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 | \*-------------------------------------------------------------------------*/ |
143 | static 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 | |||
133 | static int meth_setoption(lua_State *L) | 149 | static 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); |
@@ -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)); |
@@ -39,7 +39,7 @@ static const char *unix_tryconnect(p_unix un, const char *path); | |||
39 | static const char *unix_trybind(p_unix un, const char *path); | 39 | static const char *unix_trybind(p_unix un, const char *path); |
40 | 40 | ||
41 | /* unix object methods */ | 41 | /* unix object methods */ |
42 | static luaL_Reg un[] = { | 42 | static 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 | \*-------------------------------------------------------------------------*/ |
83 | int luaopen_socket_unix(lua_State *L) { | 83 | int 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}"); |
@@ -21,6 +21,6 @@ typedef struct t_unix_ { | |||
21 | } t_unix; | 21 | } t_unix; |
22 | typedef t_unix *p_unix; | 22 | typedef t_unix *p_unix; |
23 | 23 | ||
24 | int luaopen_socket_unix(lua_State *L); | 24 | LUASOCKET_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 | \*-------------------------------------------------------------------------*/ | ||
312 | int 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 | \*-------------------------------------------------------------------------*/ | ||
345 | int 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 | --[[ | ||
3 | Find out how many TCP connections we can make. | ||
4 | |||
5 | Use ulimit to increase the max number of descriptors: | ||
6 | |||
7 | ulimit -n 10000 | ||
8 | ulimit -n | ||
9 | |||
10 | You'll probably need to be root to do this. | ||
11 | ]] | ||
12 | |||
13 | require "socket" | ||
14 | |||
15 | host = arg[1] or "google.com" | ||
16 | port = arg[2] or 80 | ||
17 | |||
18 | connections = {} | ||
19 | |||
20 | repeat | ||
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 | |||
31 | until 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 | |||
3 | require"socket" | ||
4 | |||
5 | port = 8765 | ||
6 | |||
7 | function 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) | ||
17 | end | ||
18 | |||
19 | local m = socket.tcp() | ||
20 | |||
21 | options(m) | ||
22 | |||
23 | assert(m:bind("*", port)) | ||
24 | assert(m:listen()) | ||
25 | |||
26 | options(m) | ||
27 | |||
28 | m:close() | ||
29 | |||
30 | local m = socket.bind("*", port) | ||
31 | |||
32 | options(m) | ||
33 | |||
34 | local c = socket.connect("localhost", port) | ||
35 | |||
36 | options(c) | ||
37 | |||
38 | local s = m:accept() | ||
39 | |||
40 | options(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 | --[[ | ||
4 | Show that luasocket returns an error message on zero-length UDP sends, | ||
5 | even though the send is valid, and in fact the UDP packet is sent | ||
6 | to the peer: | ||
7 | |||
8 | % sudo tcpdump -i lo -n | ||
9 | tcpdump: verbose output suppressed, use -v or -vv for full protocol decode | ||
10 | listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes | ||
11 | 13:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0 | ||
12 | |||
13 | ]] | ||
14 | |||
15 | require"socket" | ||
16 | |||
17 | s = assert(socket.udp()) | ||
18 | r = assert(socket.udp()) | ||
19 | assert(r:setsockname("*", 5432)) | ||
20 | assert(s:setpeername("127.0.0.1", 5432)) | ||
21 | |||
22 | ssz, emsg = s:send("") | ||
23 | |||
24 | print(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 | --[[ | ||
4 | Show that luasocket returns an error message on zero-length UDP sends, | ||
5 | even though the send is valid, and in fact the UDP packet is sent | ||
6 | to the peer: | ||
7 | |||
8 | % sudo tcpdump -i lo -n | ||
9 | tcpdump: verbose output suppressed, use -v or -vv for full protocol decode | ||
10 | listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes | ||
11 | 13:40:16.652808 IP 127.0.0.1.56573 > 127.0.0.1.5432: UDP, length 0 | ||
12 | |||
13 | ]] | ||
14 | |||
15 | require"socket" | ||
16 | |||
17 | s = assert(socket.udp()) | ||
18 | r = assert(socket.udp()) | ||
19 | assert(r:setsockname("*", 5432)) | ||
20 | assert(s:setpeername("127.0.0.1", 5432)) | ||
21 | |||
22 | ok, emsg = s:send("") | ||
23 | if ok ~= 0 then | ||
24 | print("send of zero failed with:", ok, emsg) | ||
25 | end | ||
26 | |||
27 | assert(r:settimeout(2)) | ||
28 | |||
29 | ok, emsg = r:receive() | ||
30 | |||
31 | if not ok or string.len(ok) ~= 0 then | ||
32 | print("fail - receive of zero failed with:", ok, emsg) | ||
33 | os.exit(1) | ||
34 | end | ||
35 | |||
36 | print"ok" | ||
37 | |||