diff options
| author | Sam Roberts <vieuxtech@gmail.com> | 2012-04-11 14:18:20 -0700 |
|---|---|---|
| committer | Sam Roberts <vieuxtech@gmail.com> | 2012-04-11 14:18:20 -0700 |
| commit | 4b671f4551e98ac9e1d9a7407d3dffdd7eb1d3dc (patch) | |
| tree | ba92aa753ae1b145760cb1c5e69c886d3bf11328 | |
| parent | f399ab25fcecad2ff96a5977e8eaf069bb45473c (diff) | |
| parent | 195b2a74bb3f368b1f31f9c8bbc1ce0f54de2035 (diff) | |
| download | luasocket-4b671f4551e98ac9e1d9a7407d3dffdd7eb1d3dc.tar.gz luasocket-4b671f4551e98ac9e1d9a7407d3dffdd7eb1d3dc.tar.bz2 luasocket-4b671f4551e98ac9e1d9a7407d3dffdd7eb1d3dc.zip | |
Merge branch 'git-sam' into diego-sam-mwild-integration
Conflicts in options.c were just due to independent small functions
being close to each other.
unix.c in mwild was broken, it wasn't using LUASOCKET_API.
serial.c needed luaL_reg renamed, and to use LUASOCKET_API.
makefile didn't respect standard DESTDIR and prefix makefile
variables, and didn't allow LUAV variable to select lua version to build
against.
I've tested the top-level install-both target builds and installs
against both lua5.1 and lua5.2, but not done further testing.
Conflicts:
README
config
gem/ltn012.tex
makefile
src/makefile
src/options.c
src/options.h
src/tcp.c
src/usocket.c
| -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 | |||
